Skip to content

Commit

Permalink
Merge pull request #474 from ChristianTremblay/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ChristianTremblay committed Sep 16, 2024
2 parents 913364c + 71d504f commit 4ee78b2
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 71 deletions.
2 changes: 1 addition & 1 deletion BAC0/core/devices/local/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def analog(**kwargs):
"properties": {
"units": "percent",
# "eventState": EventState(),
# "covIncrement": 0.15,
"covIncrement": 0.15,
},
"presentValue": 0,
}
Expand Down
54 changes: 52 additions & 2 deletions BAC0/core/functions/Alias.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import asyncio
from typing import List, Optional, Tuple, Union

from bacpypes3.app import Application
from bacpypes3.netservice import RouterEntryStatus
from bacpypes3.npdu import RejectMessageToNetwork
from bacpypes3.pdu import Address, GlobalBroadcast

from BAC0.core.app.asyncApp import BAC0Application

from ...core.utils.notes import note_and_log

ROUTER_TUPLE_TYPE = Union[
Tuple[Union[Address, str], Union[int, List[int]]],
Tuple[Union[Address, str], Union[int, List[int]], Optional[int]],
]


@note_and_log
class Alias:
Expand Down Expand Up @@ -97,7 +105,7 @@ async def whois_router_to_network(
)
return []

async def init_routing_table(self, address):
async def init_routing_table(self, address=None):
"""
irt <addr>
Expand All @@ -108,7 +116,48 @@ async def init_routing_table(self, address):
self.log(f"Addr : {address}", level="info")
_this_application: BAC0Application = self.this_application
_app: Application = _this_application.app
await _app.nse.initialize_routing_table()
if address is not None and not isinstance(address, Address):
address = Address(address)
await _app.nse.initialize_routing_table(destination=address)

async def use_router(
self,
router_infos: Union[
Tuple[Union[Address, str], Union[int, List[int]]],
Tuple[Union[Address, str], Union[int, List[int]], Optional[int]],
] = (None, None, None),
):
address, dnets = router_infos[:2]
try:
snet = router_infos[2]
except IndexError:
snet = None
_this_application: BAC0Application = self.this_application
_app: Application = _this_application.app
if not isinstance(address, Address):
address = Address(address)
if not isinstance(dnets, list):
dnets = [dnets]
response = await self.who_is(address=address)
if response:
self._log.info(f"Router found at {address}")
self._log.info(
f"Adding router reference -> Snet : {snet} Addr : {address} dnets : {dnets}"
)
await _app.nsap.update_router_references(
snet=snet, address=address, dnets=dnets
)
self._ric = self.this_application.app.nsap.router_info_cache
self._log.info(
f"Updating router info cache -> Snet : {snet} Addr : {address} dnets : {dnets}"
)
for each in dnets:
await self._ric.set_path_info(
snet, each, address, RouterEntryStatus.available
)
_this_application._learnedNetworks.add(each)
else:
self._log.warning(f"Router not found at {address}")

async def what_is_network_number(self, destination=None, timeout=3):
"""
Expand All @@ -126,6 +175,7 @@ async def what_is_network_number(self, destination=None, timeout=3):
_app.nse.what_is_network_number(), timeout
)
return network_number

except asyncio.TimeoutError:
# Handle the timeout error
self.log(
Expand Down
3 changes: 2 additions & 1 deletion BAC0/core/functions/Discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,12 @@ async def _discover(
if reset:
self.discoveredDevices = {}
found = []
_networks = []

_this_application: BAC0Application = self.this_application
_app: Application = _this_application.app

_networks = _this_application._learnedNetworks

deviceInstanceRangeLowLimit, deviceInstanceRangeHighLimit = limits
# Try to find on which network we are
_this_network = await self.what_is_network_number()
Expand Down
2 changes: 1 addition & 1 deletion BAC0/core/io/Write.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def write()
# some debugging
_debug = 0
_LOG = ModuleLogger(globals())
WRITE_REGEX = r"(?P<address>\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|(\b\d+:\d+\b)) (?P<objId>(@obj_)?[-\w:]*[: ]*\d*) (?P<propId>(@prop_)?\w*(-\w*)?)[ ]?(?P<value>-*\w*)?[ ]?(?P<indx>-|\d*)?[ ]?(?P<priority>(1[0-6]|[0-9]))?"
WRITE_REGEX = r"(?P<address>\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?::\d+)?\b|(\b\d+:\d+\b)) (?P<objId>(@obj_)?[-\w:]*[: ]*\d*) (?P<propId>(@prop_)?\w*(-\w*)?)[ ]?(?P<value>-*\w*)?[ ]?(?P<indx>-|\d*)?[ ]?(?P<priority>(1[0-6]|[0-9]))?"
write_pattern = re.compile(WRITE_REGEX)


Expand Down
2 changes: 1 addition & 1 deletion BAC0/scripts/Base.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class Base:

def __init__(
self,
localIPAddr: str = "127.0.0.1",
localIPAddr: Address = Address("127.0.0.1/24"),
networkNumber: int = None,
localObjName: str = "BAC0",
deviceId: int = None,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "BAC0"
version = "2024.09.10"
version = "2024.09.15dev"
description = "BACnet Scripting Framework for testing DDC Controls"
authors = [{name = "Christian Tremblay", email = "[email protected]"}]
readme = "README.md"
Expand Down
40 changes: 40 additions & 0 deletions tests/manual_test_cov.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import asyncio
import random

from bacpypes3.primitivedata import Real

import BAC0
from BAC0.core.devices.local.factory import analog_value
from BAC0.scripts.script_runner import run

bacnet = None


async def main():
async with BAC0.start() as bacnet:
device = BAC0.start(port=47809, deviceId=123)

new_obj = analog_value(presentValue=0)
new_obj.add_objects_to_application(device)

# From Server
dev_av = device.this_application.app.get_object_name("AV")
print(dev_av.covIncrement)

# From client
ip = device.localIPAddr.addrTuple[0]
boid = device.Boid
bacnet._log.info("Defining device with poll 0 so the AV won't get updated")
dev = await BAC0.device(f"{ip}:47809", boid, bacnet, poll=0)
av = dev["AV"]
bacnet._log.info("Subscribing to AV")
await dev["AV"].subscribe_cov(lifetime=90)

while True:
dev_av.presentValue = Real(random.randint(1, 100))
bacnet._log.info(f"Setting AV to {dev_av.presentValue}")
await asyncio.sleep(5)


if __name__ == "__main__":
run(main, bacnet)
98 changes: 61 additions & 37 deletions tests/manual_test_create_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import random

import BAC0
from BAC0.core.devices.local.factory import (
Expand All @@ -14,7 +15,11 @@
make_state_text,
multistate_input,
multistate_output,
multistate_value,
)
from BAC0.scripts.script_runner import run

bacnet = None


def add_points(qty_per_type, device):
Expand All @@ -36,17 +41,17 @@ def add_points(qty_per_type, device):
)

states = make_state_text(["Normal", "Alarm", "Super Emergency"])
# _new_objects = multistate_value(
# description="An Alarm Value",
# properties={"stateText": states},
# name="BIG-ALARM",
# is_commandable=False,
# )
_new_objects = multistate_value(
description="An Alarm Value",
properties={"stateText": states},
name="BIG-ALARM",
is_commandable=False,
)

# All others using default implementation
for _ in range(qty_per_type):
# _new_objects = analog_output(presentValue=89.9)
_new_objects = analog_value(presentValue=79.9)
_new_objects = analog_value(presentValue=79.9, is_commandable=True)
_new_objects = binary_input()
_new_objects = binary_output()
_new_objects = binary_value()
Expand All @@ -60,36 +65,55 @@ def add_points(qty_per_type, device):


async def main():
bacnet = BAC0.lite()

# We'll use 3 devices with our first instance
device_app = BAC0.lite(port=47809, deviceId=101, localObjName="App1")
device30_app = BAC0.lite(port=47810, deviceId=102, localObjName="App2")
device300_app = BAC0.lite(port=47811, deviceId=103, localObjName="App3")

add_points(2, device_app)
add_points(3, device30_app)
add_points(4, device300_app)

ip = device_app.localIPAddr.addrTuple[0]
boid = device_app.Boid

ip_30 = device30_app.localIPAddr.addrTuple[0]
boid_30 = device30_app.Boid

ip_300 = device300_app.localIPAddr.addrTuple[0]
boid_300 = device300_app.Boid

# Connect to test device using main network
test_device = BAC0.device("{}:47809".format(ip), boid, bacnet, poll=10)
test_device_30 = BAC0.device("{}:47810".format(ip_30), boid_30, bacnet, poll=0)
test_device_300 = BAC0.device("{}:47811".format(ip_300), boid_300, bacnet, poll=0)
while True:
await asyncio.sleep(0.01)
# print(test_device.points)
# (test_device_30.points)
# (test_device_300.points)
# We'll use 3 devices plus our main instance
async with BAC0.start(localObjName="bacnet") as bacnet:
async with BAC0.start(port=47809, localObjName="App1") as device_app:
async with BAC0.start(port=47810, localObjName="App2") as device30_app:
async with BAC0.start(port=47811, localObjName="App3") as device300_app:
add_points(2, device_app)
add_points(3, device30_app)
add_points(4, device300_app)

ip = device_app.localIPAddr.addrTuple[0]
boid = device_app.Boid

ip_30 = device30_app.localIPAddr.addrTuple[0]
boid_30 = device30_app.Boid

ip_300 = device300_app.localIPAddr.addrTuple[0]
boid_300 = device300_app.Boid

# Connect to test device using main network
test_device = await BAC0.device(
f"{ip}:47809", boid, bacnet, poll=10
)
test_device_30 = await BAC0.device(
f"{ip_30}:47810", boid_30, bacnet, poll=0
)
test_device_300 = await BAC0.device(
f"{ip_300}:47811", boid_300, bacnet, poll=0
)
bacnet._log.info("CTRL-C to exit")

while True:
await asyncio.sleep(2)
bacnet._log.info(f"{test_device['BIG-ALARM']}")
new_val_for_av1 = random.randint(1, 100)
bacnet._log.info(f"Setting AV-1 to {new_val_for_av1}")
# test_device_30['AV-1'] = new_val_for_av1
await test_device_30["AV-1"].write(new_val_for_av1, priority=16)
await asyncio.sleep(2)
bacnet._log.info(
f"Forcing a read on test_device_30/AV-1 : {await test_device_30['AV-1'].value}"
)
test_device_300["AV-1"] = new_val_for_av1
await asyncio.sleep(2)
bacnet._log.info(
f"Forcing a read on test_device_300/AV-1 : {await test_device_300['AV-1'].value}"
)
# (test_device_300.points)


if __name__ == "__main__":
asyncio.run(main())
run(main, bacnet)
# asyncio.run(main())
27 changes: 0 additions & 27 deletions tests/manualtest_cov.py

This file was deleted.

0 comments on commit 4ee78b2

Please sign in to comment.