Skip to content

Commit

Permalink
Merge pull request #260 from ChristianTremblay/release_21.02.25
Browse files Browse the repository at this point in the history
Release 21.02.25
  • Loading branch information
ChristianTremblay authored Feb 25, 2021
2 parents f8bc722 + e59c385 commit d5aed21
Show file tree
Hide file tree
Showing 15 changed files with 566 additions and 455 deletions.
58 changes: 40 additions & 18 deletions BAC0/core/devices/Device.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from ...sql.sql import SQLMixin
from ...tasks.DoOnce import DoOnce
from .mixins.read_mixin import ReadPropertyMultiple, ReadProperty
from .Virtuals import VirtualPoint

from ..utils.notes import note_and_log

Expand Down Expand Up @@ -137,7 +138,7 @@ def __init__(
save_resampling="1s",
clear_history_on_save=False,
history_size=None,
reconnect_on_failure=True,
reconnect_on_failure=True
):

self.properties = DeviceProperties()
Expand Down Expand Up @@ -596,6 +597,14 @@ def __contains__(self, value):
"""
return value in self.points_name

@property
def pollable_points_name(self):
for each in self.points:
if not isinstance(each, VirtualPoint):
yield each.properties.name
else:
continue

@property
def points_name(self):
for each in self.points:
Expand Down Expand Up @@ -723,24 +732,27 @@ def read_property(self, prop):
return val

def write_property(self, prop, value, priority=None):
if priority is not None:
priority = "- {}".format(priority)
if isinstance(prop, tuple):
_obj, _instance, _prop = prop
if prop == "description":
self.update_description(value)
else:
raise ValueError(
"Please provide property using tuple with object, instance and property"
)
try:
request = "{} {} {} {} {} {}".format(
self.properties.address, _obj, _instance, _prop, value, priority
)
val = self.properties.network.write(
request, vendor_id=self.properties.vendor_id
)
except KeyError as error:
raise Exception("Unknown property : {}".format(error))
return val
if priority is not None:
priority = "- {}".format(priority)
if isinstance(prop, tuple):
_obj, _instance, _prop = prop
else:
raise ValueError(
"Please provide property using tuple with object, instance and property"
)
try:
request = "{} {} {} {} {} {}".format(
self.properties.address, _obj, _instance, _prop, value, priority
)
val = self.properties.network.write(
request, vendor_id=self.properties.vendor_id
)
except KeyError as error:
raise Exception("Unknown property : {}".format(error))
return val

def update_bacnet_properties(self):
"""
Expand Down Expand Up @@ -773,6 +785,16 @@ def _bacnet_properties(self, update=False):
def bacnet_properties(self):
return self._bacnet_properties(update=True)

def update_description(self, value):
self.properties.network.send_text_write_request(
addr=self.properties.address,
obj_type="device",
obj_inst=int(self.device_id),
value=value,
prop_id="description",
)
self.properties.description = self.read_property("description")

def __repr__(self):
return "{} / Connected".format(self.properties.name)

Expand Down
91 changes: 63 additions & 28 deletions BAC0/core/devices/Points.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

# --- standard Python modules ---
from datetime import datetime
from datetime import datetime, timedelta
from collections import namedtuple
import time

Expand Down Expand Up @@ -89,6 +89,8 @@ class Point:
is added to a history table. Histories capture the changes to point values over time.
"""

_cache_delta = timedelta(seconds=1)

def __init__(
self,
device=None,
Expand Down Expand Up @@ -130,11 +132,19 @@ def __init__(

self.cov_registered = False

self._cache = {"_previous_read": (None, None)}

@property
def value(self):
"""
Retrieve value of the point
"""
if (
self._cache["_previous_read"][0]
and datetime.now() - self._cache["_previous_read"][0] < Point._cache_delta
):
return self._cache["_previous_read"][1]

try:
res = self.properties.device.properties.network.read(
"{} {} {} presentValue".format(
Expand All @@ -147,7 +157,7 @@ def value(self):
# self._trend(res)
except Exception as e:
raise

self._cache["_previous_read"] = (datetime.now(), res)
return res

def read_priority_array(self):
Expand Down Expand Up @@ -351,33 +361,36 @@ def write(self, value, *, prop="presentValue", priority=""):
:param priority: (int) priority to which write.
"""
if priority != "":
if (
isinstance(float(priority), float)
and float(priority) >= 1
and float(priority) <= 16
):
priority = "- {}".format(priority)
else:
raise ValueError("Priority must be a number between 1 and 16")
if prop == "description":
self.update_description(value)
else:
if priority != "":
if (
isinstance(float(priority), float)
and float(priority) >= 1
and float(priority) <= 16
):
priority = "- {}".format(priority)
else:
raise ValueError("Priority must be a number between 1 and 16")

try:
self.properties.device.properties.network.write(
"{} {} {} {} {} {}".format(
self.properties.device.properties.address,
self.properties.type,
self.properties.address,
prop,
value,
priority,
),
vendor_id=self.properties.device.properties.vendor_id,
)
except NoResponseFromController:
raise
try:
self.properties.device.properties.network.write(
"{} {} {} {} {} {}".format(
self.properties.device.properties.address,
self.properties.type,
self.properties.address,
prop,
value,
priority,
),
vendor_id=self.properties.device.properties.vendor_id,
)
except NoResponseFromController:
raise

# Read after the write so history gets updated.
self.value
# Read after the write so history gets updated.
self.value

def default(self, value):
self.write(value, prop="relinquishDefault")
Expand Down Expand Up @@ -563,7 +576,9 @@ def match_value(self, value, *, delay=5, use_last_value=False):
self._match_task.running = False
time.sleep(1)

self._match_task.task = Match_Value(value=value, point=self, delay=delay)
self._match_task.task = Match_Value(
value=value, point=self, delay=delay, use_last_value=use_last_value
)
self._match_task.task.start()
self._match_task.running = True

Expand Down Expand Up @@ -598,6 +613,16 @@ def cancel_cov(self, callback=None):
address, obj_tuple, callback=callback
)

def update_description(self, value):
self.properties.device.properties.network.send_text_write_request(
addr=self.properties.device.properties.address,
obj_type=self.properties.type,
obj_inst=int(self.properties.address),
value=value,
prop_id="description",
)
self.properties.description = self.read_property("description")


# ------------------------------------------------------------------------------

Expand Down Expand Up @@ -681,15 +706,25 @@ def __repr__(self):
def __add__(self, other):
return self.value + other

__radd__ = __add__

def __sub__(self, other):
return self.value - other

def __rsub__(self, other):
return other - self.value

def __mul__(self, other):
return self.value * other

__rmul__ = __mul__

def __truediv__(self, other):
return self.value / other

def __rtruediv__(self, other):
return other / self.value

def __lt__(self, other):
return self.value < other

Expand Down
28 changes: 22 additions & 6 deletions BAC0/core/devices/Virtuals.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ def chart(self, remove=False):
self._log.warning("Use bacnet.add_trend(point) instead")

def _set(self, value):
if self._history_fn is None:
if value == "auto":
pass
elif self._history_fn is None:
self.fake_pv = value
self._trend(value)
else:
Expand Down Expand Up @@ -202,15 +204,17 @@ def history(self):
his_table.datatype = self.properties.type
return his_table

def match_value(self, value, *, delay=5):
def match_value(self, value, *, delay=5, use_last_value=False):
"""
This allow functions like :
device['point'].match('value')
A sensor will follow a calculation...
"""
if self._match_task.task is None:
self._match_task.task = Match_Value(value=value, point=self, delay=delay)
if self._match_task.task is None or not self._match_task.running:
self._match_task.task = Match_Value(
value=value, point=self, delay=delay, use_last_value=use_last_value
)
self._match_task.task.start()
self._match_task.running = True

Expand All @@ -219,7 +223,9 @@ def match_value(self, value, *, delay=5):
self._match_task.running = False
time.sleep(1)

self._match_task.task = Match_Value(value=value, point=self, delay=delay)
self._match_task.task = Match_Value(
value=value, point=self, delay=delay, use_last_value=use_last_value
)
self._match_task.task.start()
self._match_task.running = True

Expand All @@ -234,22 +240,32 @@ def __repr__(self):
return "{}/{} : {:.2f} {}".format(
self.properties.device.properties.name,
self.properties.name,
self.value,
float(self.value),
self.properties.units_state,
)

def __add__(self, other):
return self.value + other

__radd__ = __add__

def __sub__(self, other):
return self.value - other

def __rsub__(self, other):
return other - self.value

def __mul__(self, other):
return self.value * other

__rmul__ = __mul__

def __truediv__(self, other):
return self.value / other

def __rtruediv__(self, other):
return other / self.value

def __lt__(self, other):
return self.value < other

Expand Down
Loading

0 comments on commit d5aed21

Please sign in to comment.