diff --git a/{{cookiecutter.driver_name}}/python-driver/Channel.py b/{{cookiecutter.driver_name}}/python-driver/Channel.py index 199c08e..3814368 100644 --- a/{{cookiecutter.driver_name}}/python-driver/Channel.py +++ b/{{cookiecutter.driver_name}}/python-driver/Channel.py @@ -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 diff --git a/{{cookiecutter.driver_name}}/python-driver/Maps.py b/{{cookiecutter.driver_name}}/python-driver/Maps.py deleted file mode 100644 index a57347a..0000000 --- a/{{cookiecutter.driver_name}}/python-driver/Maps.py +++ /dev/null @@ -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 diff --git a/{{cookiecutter.driver_name}}/python-driver/driverConfig.json b/{{cookiecutter.driver_name}}/python-driver/driverConfig.json index a1a5484..3687826 100644 --- a/{{cookiecutter.driver_name}}/python-driver/driverConfig.json +++ b/{{cookiecutter.driver_name}}/python-driver/driverConfig.json @@ -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}}" -} \ No newline at end of file +} diff --git a/{{cookiecutter.driver_name}}/python-driver/utilities.py b/{{cookiecutter.driver_name}}/python-driver/utilities.py index cf917cb..36eef08 100644 --- a/{{cookiecutter.driver_name}}/python-driver/utilities.py +++ b/{{cookiecutter.driver_name}}/python-driver/utilities.py @@ -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."""