Adds support for multiple cookiecutter-created drivers per device

This commit is contained in:
Patrick McDonagh
2017-12-20 12:34:23 -06:00
parent 114e33cd16
commit 8e5cd8fd83
4 changed files with 154 additions and 85 deletions

View File

@@ -77,9 +77,146 @@ def write_tag(addr, tag, val):
c.close()
class Channel:
class Channel(object):
"""Holds the configuration for a Meshify channel."""
def __init__(self, mesh_name, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False):
"""Initialize the channel."""
self.mesh_name = mesh_name
self.data_type = data_type
self.last_value = None
self.value = None
self.last_send_time = 0
self.chg_threshold = chg_threshold
self.guarantee_sec = guarantee_sec
self.map_ = map_
self.write_enabled = write_enabled
def __str__(self):
"""Create a string for the channel."""
return "{}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.value, self.last_send_time)
def check(self, new_value, force_send=False):
"""Check to see if the new_value needs to be stored."""
send_needed = False
send_reason = ""
if self.data_type == 'BOOL' or self.data_type == 'STRING':
if self.last_send_time == 0:
send_needed = True
send_reason = "no send time"
elif self.value is None:
send_needed = True
send_reason = "no value"
elif not (self.value == new_value):
if self.map_:
if not self.value == self.map_[new_value]:
send_needed = True
send_reason = "value change"
else:
send_needed = True
send_reason = "value change"
elif (time.time() - self.last_send_time) > self.guarantee_sec:
send_needed = True
send_reason = "guarantee sec"
elif force_send:
send_needed = True
send_reason = "forced"
else:
if self.last_send_time == 0:
send_needed = True
send_reason = "no send time"
elif self.value is None:
send_needed = True
send_reason = "no value"
elif abs(self.value - new_value) > self.chg_threshold:
send_needed = True
send_reason = "change threshold"
elif (time.time() - self.last_send_time) > self.guarantee_sec:
send_needed = True
send_reason = "guarantee sec"
elif force_send:
send_needed = True
send_reason = "forced"
if send_needed:
self.last_value = self.value
if self.map_:
try:
self.value = self.map_[new_value]
except KeyError:
print("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name))
self.value = new_value
else:
self.value = new_value
self.last_send_time = time.time()
print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
return send_needed
def read(self):
"""Read the value."""
pass
def identity(sent):
"""Return exactly what was sent to it."""
return sent
class ModbusChannel(Channel):
"""Modbus channel object."""
def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transformFn=identity):
"""Initialize the channel."""
super(ModbusChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled)
self.mesh_name = mesh_name
self.register_number = register_number
self.channel_size = channel_size
self.data_type = data_type
self.last_value = None
self.value = None
self.last_send_time = 0
self.chg_threshold = chg_threshold
self.guarantee_sec = guarantee_sec
self.map_ = map_
self.write_enabled = write_enabled
self.transformFn = transformFn
def read(self, mbsvalue):
"""Return the transformed read value."""
return self.transformFn(mbsvalue)
class PLCChannel(Channel):
"""PLC Channel Object."""
def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False):
"""Initialize the channel."""
super(PLCChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled)
self.plc_ip = ip
self.mesh_name = mesh_name
self.plc_tag = plc_tag
self.data_type = data_type
self.last_value = None
self.value = None
self.last_send_time = 0
self.chg_threshold = chg_threshold
self.guarantee_sec = guarantee_sec
self.map_ = map_
self.write_enabled = write_enabled
def read(self):
"""Read the value."""
plc_value = None
if self.plc_tag and self.plc_ip:
read_value = read_tag(self.plc_ip, self.plc_tag)
if read_value:
plc_value = read_value[0]
return plc_value
class BoolArrayChannels(Channel):
"""Hold the configuration for a set of boolean array channels."""
def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False):
"""Initialize the channel."""
self.plc_ip = ip
@@ -94,72 +231,6 @@ class Channel:
self.map_ = map_
self.write_enabled = write_enabled
def __str__(self):
"""Create a string for the channel."""
return "{}: {}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.plc_tag, self.value, self.last_send_time)
def read(self, force_send=False):
"""Read the value and check to see if needs to be stored."""
send_needed = False
send_reason = ""
if self.plc_tag:
v = read_tag(self.plc_ip, self.plc_tag)
if v:
if self.data_type == 'BOOL' or self.data_type == 'STRING':
if self.last_send_time == 0:
send_needed = True
send_reason = "no send time"
elif self.value is None:
send_needed = True
send_reason = "no value"
elif not (self.value == v[0]):
if self.map_:
if not self.value == self.map_[v[0]]:
send_needed = True
send_reason = "value change"
else:
send_needed = True
send_reason = "value change"
elif (time.time() - self.last_send_time) > self.guarantee_sec:
send_needed = True
send_reason = "guarantee sec"
elif force_send:
send_needed = True
send_reason = "forced"
else:
if self.last_send_time == 0:
send_needed = True
send_reason = "no send time"
elif self.value is None:
send_needed = True
send_reason = "no value"
elif abs(self.value - v[0]) > self.chg_threshold:
send_needed = True
send_reason = "change threshold"
elif (time.time() - self.last_send_time) > self.guarantee_sec:
send_needed = True
send_reason = "guarantee sec"
elif force_send:
send_needed = True
send_reason = "forced"
if send_needed:
self.last_value = self.value
if self.map_:
try:
self.value = self.map_[v[0]]
except KeyError:
print("Cannot find a map value for {} in {} for {}".format(v[0], self.map_, self.mesh_name))
self.value = v[0]
else:
self.value = v[0]
self.last_send_time = time.time()
print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
return send_needed
class BoolArrayChannels(Channel):
"""Hold the configuration for a set of boolean array channels."""
def compare_values(self, new_val_dict):
"""Compare new values to old values to see if the values need storing."""
send = False

View File

@@ -1,10 +0,0 @@
"""Holds map values for {{cookiecutter.driver_name}}."""
{{cookiecutter.driver_name}}_map = {}
def reverse_map(value, map_):
"""Perform the opposite of mapping to an object."""
for x in map_:
if map_[x] == value:
return x
return None

View File

@@ -1,13 +1,12 @@
{
"name": "{{cookiecutter.driver_name}}",
"driverFilename": "{{cookiecutter.driver_name}}.py",
"driverId": "0000",
"name": "{{cookiecutter.driver_name}}",
"driverFilename": "{{cookiecutter.driver_name}}.py",
"driverId": "0000",
"additionalDriverFiles": [
"utilities.py",
"persistence.py",
"Channel.py",
"Maps.py"
],
"version": 1,
"Channel.py"
],
"version": 1,
"s3BucketName": "{{cookiecutter.driver_name}}"
}
}

View File

@@ -1,5 +1,6 @@
"""Utility functions for the driver."""
import socket
import struct
def get_public_ip_address():
@@ -10,6 +11,7 @@ def get_public_ip_address():
s.close()
return ip
def int_to_float16(int_to_convert):
"""Convert integer into float16 representation."""
bin_rep = ('0' * 16 + '{0:b}'.format(int_to_convert))[-16:]
@@ -21,6 +23,13 @@ def int_to_float16(int_to_convert):
return sign * 2 ** (exponent - 15) * float("1.{}".format(fraction))
def ints_to_float(int1, int2):
"""Convert 2 registers into a floating point number."""
mypack = struct.pack('>HH', int1, int2)
f = struct.unpack('>f', mypack)
print("[{}, {}] >> {}".format(int1, int2, f[0]))
return f[0]
def degf_to_degc(temp_f):
"""Convert deg F to deg C."""