From 059fc58ed32a2778da9fbe6c37c5aa294afc1fc6 Mon Sep 17 00:00:00 2001 From: Patrick McDonagh Date: Mon, 14 May 2018 10:29:41 -0500 Subject: [PATCH] Initial commit --- M1-Modbus-Bug.md | 76 + M1-Modbus-Bug.pdf | Bin 0 -> 32267 bytes Submonitor Modbus Points.xlsx | Bin 0 -> 23396 bytes submonitor/html-templates/Alerts.html | 1 + submonitor/html-templates/Device.html | 42 + .../html-templates/NodeDetailHeader.html | 6 + submonitor/html-templates/Nodelist.html | 39 + submonitor/html-templates/Overview.html | 308 ++ submonitor/html-templates/Sidebar.html | 15 + submonitor/html-templates/Trends.html | 37 + submonitor/python-driver/Channel.py | 287 ++ .../python-driver/channels_submonitor.csv | 42 + submonitor/python-driver/config.txt | 10 + submonitor/python-driver/device_base.py | 2 + submonitor/python-driver/driverConfig.json | 10 + submonitor/python-driver/modbusMap.p | 3367 +++++++++++++++++ submonitor/python-driver/persistence.py | 21 + submonitor/python-driver/submonitor.py | 62 + submonitor/python-driver/utilities.py | 51 + 19 files changed, 4376 insertions(+) create mode 100644 M1-Modbus-Bug.md create mode 100644 M1-Modbus-Bug.pdf create mode 100644 Submonitor Modbus Points.xlsx create mode 100644 submonitor/html-templates/Alerts.html create mode 100644 submonitor/html-templates/Device.html create mode 100644 submonitor/html-templates/NodeDetailHeader.html create mode 100644 submonitor/html-templates/Nodelist.html create mode 100644 submonitor/html-templates/Overview.html create mode 100644 submonitor/html-templates/Sidebar.html create mode 100644 submonitor/html-templates/Trends.html create mode 100644 submonitor/python-driver/Channel.py create mode 100644 submonitor/python-driver/channels_submonitor.csv create mode 100644 submonitor/python-driver/config.txt create mode 100644 submonitor/python-driver/device_base.py create mode 100644 submonitor/python-driver/driverConfig.json create mode 100644 submonitor/python-driver/modbusMap.p create mode 100644 submonitor/python-driver/persistence.py create mode 100644 submonitor/python-driver/submonitor.py create mode 100644 submonitor/python-driver/utilities.py diff --git a/M1-Modbus-Bug.md b/M1-Modbus-Bug.md new file mode 100644 index 0000000..cfaf875 --- /dev/null +++ b/M1-Modbus-Bug.md @@ -0,0 +1,76 @@ +# M1 Modbus Bug + +When adding more than one register that uses the multiplier feature, there is an error in the processing of the value. This is logged to the console: + +```python +error reading modbus value +No communication with the instrument (no answer) +Error reading register, retries exhausted +local variable 'val' referenced before assignment +Sending log to log-modbus: (X) Retries Exhausted: local variable 'val' referenced before assignment +``` + +## Steps to re-create the error + +1. Set up a single channel with no multiplier value. + +2. Set Modbus settings and Sync to Device. + + ``` + here is the answer + �� + '\xf7\x03\x02\x13\x16\xfc\xaf' + '\xf7\x03\x02\x13\x16\xfc\xaf' + here is the payload from slave + + '\x02\x13\x16' + here is the payload + + '\x02\x13\x16' + success reading + 4886 + 4886 + ``` + +3. Set up another channel with Multiplier parameter of "Divide" and Multiplier Value of "10". + +4. Sync to Device. + + on first register: + + ``` + here is the answer + + '' + '' + error reading modbus value + No communication with the instrument (no answer) + had an error on the modbus loop, retrying read + here is your period: 120 + 23.4706990719 + here is your send value: False + getting int + writing 485: �,P� + ``` + + on second register: + + ``` + here is the answer + + '' + '' + error reading modbus value + No communication with the instrument (no answer) + Error reading register, retries exhausted + local variable 'val' referenced before assignment + here is your period: 120 + 1525193769.02 + here is your send value: True + getting int + writing 485: �7 � + ``` + + + + diff --git a/M1-Modbus-Bug.pdf b/M1-Modbus-Bug.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3d31b4507f05c6d41f961bd53565bd6727852139 GIT binary patch literal 32267 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 D5iA$8 literal 0 HcmV?d00001 diff --git a/Submonitor Modbus Points.xlsx b/Submonitor Modbus Points.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9f1c20afe32981e77c2cee40de4ede88a7d0ec54 GIT binary patch literal 23396 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 literal 0 HcmV?d00001 diff --git a/submonitor/html-templates/Alerts.html b/submonitor/html-templates/Alerts.html new file mode 100644 index 0000000..2971cab --- /dev/null +++ b/submonitor/html-templates/Alerts.html @@ -0,0 +1 @@ +Alerts diff --git a/submonitor/html-templates/Device.html b/submonitor/html-templates/Device.html new file mode 100644 index 0000000..0797f12 --- /dev/null +++ b/submonitor/html-templates/Device.html @@ -0,0 +1,42 @@ +
+
+

Public IP Address

+

<%= channels["submonitor.public_ip_address"].value %>

+

+
+ + diff --git a/submonitor/html-templates/NodeDetailHeader.html b/submonitor/html-templates/NodeDetailHeader.html new file mode 100644 index 0000000..28262a3 --- /dev/null +++ b/submonitor/html-templates/NodeDetailHeader.html @@ -0,0 +1,6 @@ +
+
+
+
+

<%= node.vanityname %>

+
diff --git a/submonitor/html-templates/Nodelist.html b/submonitor/html-templates/Nodelist.html new file mode 100644 index 0000000..1622f37 --- /dev/null +++ b/submonitor/html-templates/Nodelist.html @@ -0,0 +1,39 @@ + + +
+
+
+
+ +
+ +
+ +
+

<%= node.vanityname %>

+
+
+

Avg. Current

+

<%= Math.round(channels['submonitor.current_average'].value * 100) / 100 %> A.

+
+
+

Avg. Voltage

+

<%= Math.round(channels['submonitor.voltage_average'].value * 100) / 100 %> V.

+
+
diff --git a/submonitor/html-templates/Overview.html b/submonitor/html-templates/Overview.html new file mode 100644 index 0000000..c559cf4 --- /dev/null +++ b/submonitor/html-templates/Overview.html @@ -0,0 +1,308 @@ +
+
+
+ +
+ +
+
+
+ +
+
+
+

Voltage

+
+
+ +
+
+ +
+ +
+
+ +
+
+
+
+
+
+ +
+ +
+
+
+

Current

+
+
+ +
+
+ +
+ +
+
+ +
+
+
+
+
+
+ +
+ + + + + + + + + diff --git a/submonitor/html-templates/Sidebar.html b/submonitor/html-templates/Sidebar.html new file mode 100644 index 0000000..de8f1af --- /dev/null +++ b/submonitor/html-templates/Sidebar.html @@ -0,0 +1,15 @@ +" + class="data-table btn-block btn btn-theme animated" + title="Device Log"> Device Log + +" + data-techname="<%=channels["submonitor.sync"].techName %>" + data-name="<%= channels["submonitor.sync"].name%>" + data-nodechannelcurrentId="<%= channels["submonitor.sync"].nodechannelcurrentId %>" + id="<%= channels["submonitor.sync"].channelId %>" + class="btn btn-large btn-block btn-theme animated setstatic mqtt"> + Sync All Data diff --git a/submonitor/html-templates/Trends.html b/submonitor/html-templates/Trends.html new file mode 100644 index 0000000..744ce61 --- /dev/null +++ b/submonitor/html-templates/Trends.html @@ -0,0 +1,37 @@ +
+
+ + to + + + Run + +
+
+
+
+
+ diff --git a/submonitor/python-driver/Channel.py b/submonitor/python-driver/Channel.py new file mode 100644 index 0000000..adb6680 --- /dev/null +++ b/submonitor/python-driver/Channel.py @@ -0,0 +1,287 @@ +"""Define Meshify channel class.""" +from pycomm.ab_comm.clx import Driver as ClxDriver +from pycomm.cip.cip_base import CommError, DataError +import time + + +def binarray(intval): + """Split an integer into its bits.""" + bin_string = '{0:08b}'.format(intval) + bin_arr = [i for i in bin_string] + bin_arr.reverse() + return bin_arr + + +def read_tag(addr, tag, plc_type="CLX"): + """Read a tag from the PLC.""" + direct = plc_type == "Micro800" + c = ClxDriver() + try: + if c.open(addr, direct_connection=direct): + try: + v = c.read_tag(tag) + return v + except DataError as e: + c.close() + print("Data Error during readTag({}, {}): {}".format(addr, tag, e)) + except CommError: + # err = c.get_status() + c.close() + print("Could not connect during readTag({}, {})".format(addr, tag)) + # print err + except AttributeError as e: + c.close() + print("AttributeError during readTag({}, {}): \n{}".format(addr, tag, e)) + c.close() + return False + + +def read_array(addr, tag, start, end, plc_type="CLX"): + """Read an array from the PLC.""" + direct = plc_type == "Micro800" + c = ClxDriver() + if c.open(addr, direct_connection=direct): + arr_vals = [] + try: + for i in range(start, end): + tag_w_index = tag + "[{}]".format(i) + v = c.read_tag(tag_w_index) + # print('{} - {}'.format(tag_w_index, v)) + arr_vals.append(round(v[0], 4)) + # print(v) + if len(arr_vals) > 0: + return arr_vals + else: + print("No length for {}".format(addr)) + return False + except Exception: + print("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) + err = c.get_status() + c.close() + print err + pass + c.close() + + +def write_tag(addr, tag, val, plc_type="CLX"): + """Write a tag value to the PLC.""" + direct = plc_type == "Micro800" + c = ClxDriver() + if c.open(addr, direct_connection=direct): + try: + cv = c.read_tag(tag) + print(cv) + wt = c.write_tag(tag, val, cv[1]) + return wt + except Exception: + print("Error during writeTag({}, {}, {})".format(addr, tag, val)) + err = c.get_status() + c.close() + print err + c.close() + + +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, plc_type='CLX'): + """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 + self.plc_type = plc_type + + 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, plc_type=self.plc_type) + 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 + 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 compare_values(self, new_val_dict): + """Compare new values to old values to see if the values need storing.""" + send = False + for idx in new_val_dict: + try: + if new_val_dict[idx] != self.last_value[idx]: + send = True + except KeyError: + print("Key Error in self.compare_values for index {}".format(idx)) + send = True + return send + + 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: + bool_arr = binarray(v[0]) + new_val = {} + for idx in self.map_: + try: + new_val[self.map_[idx]] = bool_arr[idx] + except KeyError: + print("Not able to get value for index {}".format(idx)) + + 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 self.compare_values(new_val): + 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" + + if send_needed: + self.value = new_val + self.last_value = self.value + self.last_send_time = time.time() + print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) + return send_needed diff --git a/submonitor/python-driver/channels_submonitor.csv b/submonitor/python-driver/channels_submonitor.csv new file mode 100644 index 0000000..6617bfb --- /dev/null +++ b/submonitor/python-driver/channels_submonitor.csv @@ -0,0 +1,42 @@ +id,name,deviceTypeId,fromMe,io,subTitle,helpExplanation,channelType,dataType,defaultValue,regex,regexErrMsg,units,min,max,change,guaranteedReportPeriod,minReportTime +13648,log,462,FALSE,readonly,Log,Device Log,device,string,Initialized,,,,,,,, +13650,voltage_average,462,FALSE,readonly,Average Voltage,Volts,device,float,,,,,,,,, +13651,voltage_ab,462,FALSE,readonly,Voltage: A-B,Volts,device,float,,,,,,,,, +13652,voltage_bc,462,FALSE,readonly,Voltage: B-C,Volts,device,float,,,,,,,,, +13653,voltage_ca,462,FALSE,readonly,Voltage: C-A,Volts,device,float,,,,,,,,, +13654,voltage_ln,462,FALSE,readonly,Voltage: L-N,Volts,device,float,,,,,,,,, +13655,frequency,462,FALSE,readonly,Frequency,Hz,device,float,,,,,,,,, +13656,phase_order,462,FALSE,readonly,Phase Order,ABC/ACB,device,string,,,,,,,,, +13657,voltage_unbalance,462,FALSE,readonly,Voltage Unbalance,%,device,float,,,,,,,,, +13658,voltage_ab_min,462,FALSE,readonly,Voltage Min: A-B,Volts,device,float,,,,,,,,, +13659,voltage_bc_min,462,FALSE,readonly,Voltage Min: B-C,Volts,device,float,,,,,,,,, +13660,voltage_ca_min,462,FALSE,readonly,Voltage Min: C-A,Volts,device,float,,,,,,,,, +13661,current_average,462,FALSE,readonly,Average Current,Amps,device,float,,,,,,,,, +13662,current_a,462,FALSE,readonly,Current: A Phase,Amps,device,float,,,,,,,,, +13663,current_b,462,FALSE,readonly,Current: B Phase,Amps,device,float,,,,,,,,, +13664,current_c,462,FALSE,readonly,Current: C Phase,Amps,device,float,,,,,,,,, +13665,current_ground,462,FALSE,readonly,Current: Ground,Amps,device,float,,,,,,,,, +13666,current_unbalance,462,FALSE,readonly,Current Unbalance,%,device,float,,,,,,,,, +13667,current_peak,462,FALSE,readonly,Peak Current,Amps,device,float,,,,,,,,, +13668,power_kw,462,FALSE,readonly,Power: kW,kW,device,float,,,,,,,,, +13669,power_kva,462,FALSE,readonly,Power: kVA,kVA,device,float,,,,,,,,, +13670,power_kvar,462,FALSE,readonly,Power: kVAR,kVAR,device,float,,,,,,,,, +13671,power_pf_average,462,FALSE,readonly,Power Factor: Average,pf,device,float,,,,,,,,, +13672,power_pf_a,462,FALSE,readonly,Power Factor: A Phase,pf,device,float,,,,,,,,, +13673,power_pf_b,462,FALSE,readonly,Power Factor: B Phase,pf,device,float,,,,,,,,, +13674,power_pf_c,462,FALSE,readonly,Power Factor C Phase,pf,device,float,,,,,,,,, +13675,power_kwh,462,FALSE,readonly,Power: kWh Elapsed,kWh,device,float,,,,,,,,, +13676,motor_insulation,462,FALSE,readonly,Motor Insulation,Ohms,device,float,,,,,,,,, +13677,motor_temp_rtd,462,FALSE,readonly,Motor Temp RTD,deg,device,float,,,,,,,,, +13678,motor_temp_subtrolx,462,FALSE,readonly,Motor Temp SubtrolX,deg,device,float,,,,,,,,, +,system_state,462,FALSE,readonly,System State,state,device,string,,,,,,,,, +,hoa_mode,462,FALSE,readonly,HOA Mode,state,device,string,,,,,,,,, +,motor_state,462,FALSE,readonly,Motor State,state,device,string,,,,,,,,, +,fault_current,462,FALSE,readonly,Current Fault,fault,device,string,,,,,,,,, +,alarm_1,462,FALSE,readonly,Alarm 1,alarm,device,string,,,,,,,,, +,alarm_2,462,FALSE,readonly,Alarm 2,alarm,device,string,,,,,,,,, +,alarm_3,462,FALSE,readonly,Alarm 3,alarm,device,string,,,,,,,,, +,alarm_4,462,FALSE,readonly,Alarm 4,alarm,device,string,,,,,,,,, +,alarm_5,462,FALSE,readonly,Alarm 5,alarm,device,string,,,,,,,,, +,terminal_v1_v2,462,FALSE,readonly,V1/V2 Terminal,on/off,device,string,,,,,,,,, +,motor_run_Time,462,FALSE,readonly,Motor Run Time,hours,device,float,,,,,,,,, \ No newline at end of file diff --git a/submonitor/python-driver/config.txt b/submonitor/python-driver/config.txt new file mode 100644 index 0000000..1546190 --- /dev/null +++ b/submonitor/python-driver/config.txt @@ -0,0 +1,10 @@ +{ + "driverFileName": "submonitor.py", + "deviceName": "submonitor", + "driverId": "0210", + "releaseVersion": "2", + "files": { + "file1": "submonitor.py", + "file2": "modbusMap.p" + } +} \ No newline at end of file diff --git a/submonitor/python-driver/device_base.py b/submonitor/python-driver/device_base.py new file mode 100644 index 0000000..edbd53d --- /dev/null +++ b/submonitor/python-driver/device_base.py @@ -0,0 +1,2 @@ +class deviceBase(object): + pass \ No newline at end of file diff --git a/submonitor/python-driver/driverConfig.json b/submonitor/python-driver/driverConfig.json new file mode 100644 index 0000000..b44dcef --- /dev/null +++ b/submonitor/python-driver/driverConfig.json @@ -0,0 +1,10 @@ +{ + "name": "submonitor", + "driverFilename": "submonitor.py", + "driverId": "0210", + "additionalDriverFiles": [ + "modbusMap.p" + ], + "version": 2, + "s3BucketName": "submonitor" +} \ No newline at end of file diff --git a/submonitor/python-driver/modbusMap.p b/submonitor/python-driver/modbusMap.p new file mode 100644 index 0000000..06700df --- /dev/null +++ b/submonitor/python-driver/modbusMap.p @@ -0,0 +1,3367 @@ +(dp0 +S'1' +p1 +(dp2 +S'c' +p3 +VM1-485 +p4 +sS'b' +p5 +V19200 +p6 +sS'addresses' +p7 +(dp8 +V247 +p9 +(dp10 +V2-34 +p11 +(dp12 +Val +p13 +V +p14 +sVah +p15 +g14 +sVbytary +p16 +NsVvm +p17 +NsVvn +p18 +VAlarm 1 +p19 +sVct +p20 +Vnumber +p21 +sVle +p22 +V16 +p23 +sVgrp +p24 +V600 +p25 +sVla +p26 +S'' +p27 +sVchn +p28 +Valarm_1 +p29 +sVun +p30 +V1 +p31 +sVdn +p32 +Vsubmonitor +p33 +sVda +p34 +V247 +p35 +sVlrt +p36 +V0 +p37 +sVr +p38 +V0-65535 +p39 +sVa +p40 +V204 +p41 +sVc +p42 +g31 +sVmisc_u +p43 +g14 +sVf +p44 +V3 +p45 +sVmrt +p46 +V10 +p47 +sVm +p48 +Vnone +p49 +sS'm1ch' +p50 +g11 +sVs +p51 +VOn +p52 +sVmv +p53 +g37 +sVt +p54 +Vint +p55 +ssV2-32 +p56 +(dp57 +Val +p58 +g14 +sVah +p59 +g14 +sVbytary +p60 +NsVvm +p61 +NsVvn +p62 +VMotor State +p63 +sVct +p64 +Vnumber +p65 +sVle +p66 +V16 +p67 +sVgrp +p68 +V600 +p69 +sVla +p70 +g27 +sVchn +p71 +Vmotor_state +p72 +sVun +p73 +g31 +sVdn +p74 +Vsubmonitor +p75 +sVda +p76 +V247 +p77 +sVlrt +p78 +F1525815076.4383951 +sg38 +V0-65535 +p79 +sg40 +V202 +p80 +sg42 +g31 +sVmisc_u +p81 +g14 +sg44 +g45 +sVmrt +p82 +V10 +p83 +sg48 +Vnone +p84 +sg50 +g56 +sg51 +VOn +p85 +sVmv +p86 +g37 +sg54 +Vint +p87 +ssV2-33 +p88 +(dp89 +Val +p90 +g14 +sVah +p91 +g14 +sVbytary +p92 +NsVvm +p93 +NsVvn +p94 +VFault State +p95 +sVct +p96 +Vnumber +p97 +sVle +p98 +V16 +p99 +sVgrp +p100 +V600 +p101 +sVla +p102 +g27 +sVchn +p103 +Vfault_current +p104 +sVun +p105 +g31 +sVdn +p106 +Vsubmonitor +p107 +sVda +p108 +V247 +p109 +sVlrt +p110 +g37 +sg38 +V0-65535 +p111 +sg40 +V203 +p112 +sg42 +g31 +sVmisc_u +p113 +g14 +sg44 +g45 +sVmrt +p114 +V10 +p115 +sg48 +Vnone +p116 +sg50 +g88 +sg51 +VOn +p117 +sVmv +p118 +g37 +sg54 +Vint +p119 +ssV2-35 +p120 +(dp121 +Val +p122 +g14 +sVah +p123 +g14 +sVbytary +p124 +NsVvm +p125 +NsVvn +p126 +VAlarm 2 +p127 +sVct +p128 +Vnumber +p129 +sVle +p130 +V16 +p131 +sVgrp +p132 +V600 +p133 +sVla +p134 +g27 +sVchn +p135 +Valarm_2 +p136 +sVun +p137 +g31 +sVdn +p138 +Vsubmonitor +p139 +sVda +p140 +V247 +p141 +sVlrt +p142 +g37 +sg38 +V0-65535 +p143 +sg40 +V205 +p144 +sg42 +g31 +sVmisc_u +p145 +g14 +sg44 +g45 +sVmrt +p146 +V10 +p147 +sg48 +Vnone +p148 +sg50 +g120 +sg51 +VOn +p149 +sVmv +p150 +g37 +sg54 +Vint +p151 +ssV2-30 +p152 +(dp153 +Val +p154 +g14 +sVah +p155 +g14 +sVbytary +p156 +NsVvm +p157 +NsVvn +p158 +VSystem State +p159 +sVct +p160 +Vnumber +p161 +sVle +p162 +V16 +p163 +sVgrp +p164 +V600 +p165 +sVla +p166 +g27 +sVchn +p167 +Vsystem_state +p168 +sVun +p169 +g31 +sVdn +p170 +Vsubmonitor +p171 +sVda +p172 +V247 +p173 +sVlrt +p174 +F1525815076.965099 +sg38 +V0-65535 +p175 +sg40 +V200 +p176 +sg42 +g31 +sVmisc_u +p177 +g14 +sg44 +g45 +sVmrt +p178 +V10 +p179 +sg48 +Vnone +p180 +sg50 +g152 +sg51 +VOn +p181 +sVmv +p182 +g37 +sg54 +Vint +p183 +ssV2-31 +p184 +(dp185 +Val +p186 +g14 +sVah +p187 +g14 +sVbytary +p188 +NsVvm +p189 +NsVvn +p190 +VHOA Mode +p191 +sVct +p192 +Vnumber +p193 +sVle +p194 +V16 +p195 +sVgrp +p196 +V600 +p197 +sVla +p198 +g27 +sVchn +p199 +Vhoa_mode +p200 +sVun +p201 +g31 +sVdn +p202 +Vsubmonitor +p203 +sVda +p204 +V247 +p205 +sVlrt +p206 +F1525815077.6294771 +sg38 +V0-65535 +p207 +sg40 +V201 +p208 +sg42 +g31 +sVmisc_u +p209 +g14 +sg44 +g45 +sVmrt +p210 +V10 +p211 +sg48 +Vnone +p212 +sg50 +g184 +sg51 +VOn +p213 +sVmv +p214 +g37 +sg54 +Vint +p215 +ssV2-29 +p216 +(dp217 +Vah +p218 +g14 +sVbytary +p219 +NsVal +p220 +g14 +sVvn +p221 +VMotor Temp: SubtrolX +p222 +sVct +p223 +Vnumber +p224 +sVle +p225 +V16 +p226 +sVgrp +p227 +V600 +p228 +sVla +p229 +g27 +sVchn +p230 +Vmotor_temp_subtrolx +p231 +sVun +p232 +V1 +p233 +sVdn +p234 +Vsubmonitor +p235 +sVvm +p236 +NsVlrt +p237 +F1525815078.1144631 +sVda +p238 +V247 +p239 +sVa +p240 +V329 +p241 +sVc +p242 +g233 +sVmisc_u +p243 +Vdeg +p244 +sVf +p245 +V3 +p246 +sVmrt +p247 +V10 +p248 +sVm +p249 +Vdivide +p250 +sS'm1ch' +p251 +g216 +sVmv +p252 +V10 +p253 +sVs +p254 +VOn +p255 +sVr +p256 +V0-500 +p257 +sVt +p258 +Vint +p259 +ssV2-28 +p260 +(dp261 +g38 +V0-5000 +p262 +sVah +p263 +g14 +sVbytary +p264 +NsVal +p265 +g14 +sVvn +p266 +VMotor Temp: RTD +p267 +sVct +p268 +Vnumber +p269 +sVle +p270 +V16 +p271 +sVgrp +p272 +V600 +p273 +sVla +p274 +g27 +sVchn +p275 +Vmotor_temp_rtd +p276 +sVun +p277 +g31 +sVdn +p278 +Vsubmonitor +p279 +sVvm +p280 +NsVlrt +p281 +g37 +sVda +p282 +V247 +p283 +sg40 +V328 +p284 +sg42 +g31 +sVmisc_u +p285 +Vdeg +p286 +sg44 +g45 +sVmrt +p287 +V10 +p288 +sg48 +Vdivide +p289 +sVm1ch +p290 +g260 +sg51 +VOn +p291 +sVmv +p292 +V10 +p293 +sg54 +Vint +p294 +ssV2-25 +p295 +(dp296 +Vah +p297 +g14 +sVbytary +p298 +NsVal +p299 +g14 +sVvn +p300 +VPower: PF C +p301 +sVct +p302 +Vnumber +p303 +sVle +p304 +V16 +p305 +sVgrp +p306 +V600 +p307 +sVla +p308 +g27 +sVchn +p309 +Vpower_pf_c +p310 +sVun +p311 +g233 +sVdn +p312 +Vsubmonitor +p313 +sVvm +p314 +NsVlrt +p315 +F1525815079.810442 +sVda +p316 +V247 +p317 +sg240 +V324 +p318 +sg242 +g233 +sVmisc_u +p319 +V% +p320 +sg245 +g246 +sVmrt +p321 +V10 +p322 +sg249 +Vdivide +p323 +sg251 +g295 +sVmv +p324 +V10 +p325 +sg254 +VOn +p326 +sg256 +V0-100 +p327 +sg258 +Vint +p328 +ssV2-24 +p329 +(dp330 +Vah +p331 +g14 +sVbytary +p332 +NsVal +p333 +g14 +sVvn +p334 +VPower: PF B +p335 +sVct +p336 +Vnumber +p337 +sVle +p338 +V16 +p339 +sVgrp +p340 +V600 +p341 +sVla +p342 +g27 +sVchn +p343 +Vpower_pf_b +p344 +sVun +p345 +g233 +sVdn +p346 +Vsubmonitor +p347 +sVvm +p348 +NsVlrt +p349 +F1525815080.344325 +sVda +p350 +V247 +p351 +sg240 +V323 +p352 +sg242 +g233 +sVmisc_u +p353 +g320 +sg245 +g246 +sVmrt +p354 +V10 +p355 +sg249 +Vdivide +p356 +sg251 +g329 +sVmv +p357 +V10 +p358 +sg254 +VOn +p359 +sg256 +V0-100 +p360 +sg258 +Vint +p361 +ssV2-27 +p362 +(dp363 +g38 +V0-65535 +p364 +sVah +p365 +g14 +sVbytary +p366 +NsVal +p367 +g14 +sVvn +p368 +VMotor Insulation +p369 +sVct +p370 +Vnumber +p371 +sVle +p372 +V16 +p373 +sVgrp +p374 +V600 +p375 +sVla +p376 +g27 +sVchn +p377 +Vmotor_insulation +p378 +sVun +p379 +g31 +sVdn +p380 +Vsubmonitor +p381 +sVvm +p382 +NsVlrt +p383 +F1525815080.82966 +sVda +p384 +V247 +p385 +sg40 +V327 +p386 +sg42 +g31 +sVmisc_u +p387 +VOhms +p388 +sg44 +g45 +sVmrt +p389 +V10 +p390 +sg48 +Vnone +p391 +sVm1ch +p392 +g362 +sg51 +VOn +p393 +sVmv +p394 +V10 +p395 +sg54 +Vint +p396 +ssV2-26 +p397 +(dp398 +Vah +p399 +g14 +sVbytary +p400 +NsVal +p401 +g14 +sVvn +p402 +VPower: kWh +p403 +sVct +p404 +Vnumber +p405 +sVle +p406 +V32 +p407 +sVgrp +p408 +V600 +p409 +sVla +p410 +g27 +sVchn +p411 +Vpower_kwh +p412 +sVun +p413 +g233 +sVdn +p414 +Vsubmonitor +p415 +sVvm +p416 +NsVlrt +p417 +F1525815081.4780059 +sVda +p418 +V247 +p419 +sg240 +V325 +p420 +sg242 +V100 +p421 +sVmisc_u +p422 +VkWh +p423 +sg245 +g246 +sVmrt +p424 +V10 +p425 +sg249 +Vnone +p426 +sg251 +g397 +sVmv +p427 +V0 +p428 +sg254 +VOn +p429 +sg256 +V0-1000000 +p430 +sg258 +Vfloat +p431 +ssV2-21 +p432 +(dp433 +Vah +p434 +g14 +sVbytary +p435 +NsVal +p436 +g14 +sVvn +p437 +VPower: kVAR +p438 +sVct +p439 +Vnumber +p440 +sVle +p441 +V16 +p442 +sVgrp +p443 +V600 +p444 +sVla +p445 +g27 +sVchn +p446 +Vpower_kvar +p447 +sVun +p448 +g233 +sVdn +p449 +Vsubmonitor +p450 +sVvm +p451 +NsVlrt +p452 +F1525815081.964795 +sVda +p453 +V247 +p454 +sg240 +V320 +p455 +sg242 +V5 +p456 +sVmisc_u +p457 +VkVAR +p458 +sg245 +g246 +sVmrt +p459 +V10 +p460 +sg249 +Vdivide +p461 +sg251 +g432 +sVmv +p462 +V10 +p463 +sg254 +VOn +p464 +sg256 +V0-65535 +p465 +sg258 +Vint +p466 +ssV2-20 +p467 +(dp468 +Vah +p469 +g14 +sVbytary +p470 +NsVal +p471 +g14 +sVvn +p472 +VPower: kVA +p473 +sVct +p474 +Vnumber +p475 +sVle +p476 +V16 +p477 +sVgrp +p478 +V600 +p479 +sVla +p480 +g27 +sVchn +p481 +Vpower_kva +p482 +sVun +p483 +g233 +sVdn +p484 +Vsubmonitor +p485 +sVvm +p486 +NsVlrt +p487 +F1525815082.4758321 +sVda +p488 +V247 +p489 +sg240 +V319 +p490 +sg242 +g456 +sVmisc_u +p491 +VkVA +p492 +sg245 +g246 +sVmrt +p493 +V10 +p494 +sg249 +Vdivide +p495 +sg251 +g467 +sVmv +p496 +V10 +p497 +sg254 +VOn +p498 +sg256 +V0-65535 +p499 +sg258 +Vint +p500 +ssV2-23 +p501 +(dp502 +Vah +p503 +g14 +sVbytary +p504 +NsVal +p505 +g14 +sVvn +p506 +VPower: PF A +p507 +sVct +p508 +Vnumber +p509 +sVle +p510 +V16 +p511 +sVgrp +p512 +V600 +p513 +sVla +p514 +g27 +sVchn +p515 +Vpower_pf_a +p516 +sVun +p517 +g233 +sVdn +p518 +Vsubmonitor +p519 +sVvm +p520 +NsVlrt +p521 +F1525815082.9779911 +sVda +p522 +V247 +p523 +sg240 +V322 +p524 +sg242 +g233 +sVmisc_u +p525 +g320 +sg245 +g246 +sVmrt +p526 +V10 +p527 +sg249 +Vdivide +p528 +sg251 +g501 +sVmv +p529 +V10 +p530 +sg254 +VOn +p531 +sg256 +V0-100 +p532 +sg258 +Vint +p533 +ssV2-22 +p534 +(dp535 +Vah +p536 +g14 +sVbytary +p537 +NsVal +p538 +g14 +sVvn +p539 +VPower: PF Average +p540 +sVct +p541 +Vnumber +p542 +sVle +p543 +V16 +p544 +sVgrp +p545 +V600 +p546 +sVla +p547 +g27 +sVchn +p548 +Vpower_pf_average +p549 +sVun +p550 +g233 +sVdn +p551 +Vsubmonitor +p552 +sVvm +p553 +NsVlrt +p554 +F1525815083.4619391 +sVda +p555 +V247 +p556 +sg240 +V321 +p557 +sg242 +g233 +sVmisc_u +p558 +g14 +sg245 +g246 +sVmrt +p559 +V10 +p560 +sg249 +Vdivide +p561 +sg251 +g534 +sVmv +p562 +V10 +p563 +sg254 +VOn +p564 +sg256 +V0-100 +p565 +sg258 +Vint +p566 +ssV2-2 +p567 +(dp568 +Vah +p569 +g14 +sVbytary +p570 +NsVal +p571 +g14 +sVvn +p572 +VAverage Current +p573 +sVct +p574 +Vnumber +p575 +sVle +p576 +V16 +p577 +sVgrp +p578 +V600 +p579 +sVla +p580 +g27 +sVchn +p581 +Vcurrent_average +p582 +sVun +p583 +g233 +sVdn +p584 +Vsubmonitor +p585 +sVda +p586 +V247 +p587 +sVlrt +p588 +F1525815084.007163 +sg256 +V0-250 +p589 +sg240 +V311 +p590 +sg242 +g233 +sVmisc_u +p591 +VA +p592 +sg245 +g246 +sVmrt +p593 +V10 +p594 +sg249 +Vdivide +p595 +sVm1ch +p596 +g567 +sg254 +VOn +p597 +sVmv +p598 +V10 +p599 +sg258 +Vint +p600 +sVvm +p601 +NssV2-3 +p602 +(dp603 +Vah +p604 +g14 +sVbytary +p605 +NsVal +p606 +g14 +sVvn +p607 +VVoltage: A-B +p608 +sVct +p609 +Vnumber +p610 +sVle +p611 +V16 +p612 +sVgrp +p613 +V600 +p614 +sVla +p615 +g27 +sVchn +p616 +Vvoltage_ab +p617 +sVun +p618 +g31 +sVdn +p619 +Vsubmonitor +p620 +sVda +p621 +V247 +p622 +sVlrt +p623 +F1525815497.5719991 +sg38 +V0-600 +p624 +sg40 +V301 +p625 +sg42 +V2.0 +p626 +sVmisc_u +p627 +VV +p628 +sg44 +g45 +sVmrt +p629 +V10 +p630 +sg48 +Vdivide +p631 +sVm1ch +p632 +g602 +sg51 +VOn +p633 +sVmv +p634 +V10 +p635 +sg54 +Vint +p636 +sVvm +p637 +NssV2-1 +p638 +(dp639 +Vah +p640 +g14 +sVbytary +p641 +NsVal +p642 +g14 +sVvn +p643 +VAverage Voltage +p644 +sVct +p645 +Vnumber +p646 +sVle +p647 +V16 +p648 +sVgrp +p649 +V600 +p650 +sVla +p651 +g27 +sVchn +p652 +Vvoltage_average +p653 +sg256 +V0-600 +p654 +sVun +p655 +g233 +sVdn +p656 +Vsubmonitor +p657 +sVda +p658 +V247 +p659 +sVlrt +p660 +F1525815498.0583251 +sg240 +V300 +p661 +sg242 +V2.0 +p662 +sVmisc_u +p663 +VV +p664 +sg245 +g246 +sVmrt +p665 +V10 +p666 +sg249 +Vdivide +p667 +sVm1ch +p668 +g638 +sg254 +VOn +p669 +sVmv +p670 +V10 +p671 +sg258 +Vint +p672 +sVvm +p673 +NssV2-6 +p674 +(dp675 +Vah +p676 +g14 +sVbytary +p677 +NsVal +p678 +g14 +sVvn +p679 +VVoltage: L-N +p680 +sVct +p681 +Vnumber +p682 +sVle +p683 +V16 +p684 +sVgrp +p685 +V600 +p686 +sVla +p687 +g27 +sVchn +p688 +Vvoltage_ln +p689 +sVun +p690 +g233 +sVdn +p691 +Vsubmonitor +p692 +sVvm +p693 +NsVlrt +p694 +F1525815085.4837161 +sVda +p695 +V247 +p696 +sg240 +V304 +p697 +sg242 +V2 +p698 +sVmisc_u +p699 +g664 +sg245 +g246 +sVmrt +p700 +V10 +p701 +sg249 +Vdivide +p702 +sg251 +g674 +sVmv +p703 +V10 +p704 +sg254 +VOn +p705 +sg256 +V0-600 +p706 +sg258 +Vint +p707 +ssV2-7 +p708 +(dp709 +Vah +p710 +g14 +sVbytary +p711 +NsVal +p712 +g14 +sVvn +p713 +VFrequency +p714 +sVct +p715 +Vnumber +p716 +sVle +p717 +V16 +p718 +sVgrp +p719 +V600 +p720 +sVla +p721 +g27 +sVchn +p722 +Vfrequency +p723 +sVun +p724 +g233 +sVdn +p725 +Vsubmonitor +p726 +sVvm +p727 +NsVlrt +p728 +F1525814970.4699421 +sVda +p729 +V247 +p730 +sg240 +V305 +p731 +sg242 +V0.5 +p732 +sVmisc_u +p733 +VHz +p734 +sg245 +g246 +sVmrt +p735 +V10 +p736 +sg249 +Vdivide +p737 +sg251 +g708 +sVmv +p738 +V10 +p739 +sg254 +VOn +p740 +sg256 +V0-100 +p741 +sg258 +Vint +p742 +ssV2-4 +p743 +(dp744 +Vah +p745 +g14 +sVbytary +p746 +NsVal +p747 +g14 +sVvn +p748 +VVoltage: B-C +p749 +sVct +p750 +Vnumber +p751 +sVle +p752 +V16 +p753 +sVgrp +p754 +V600 +p755 +sVla +p756 +g27 +sVchn +p757 +Vvoltage_bc +p758 +sVun +p759 +g233 +sVdn +p760 +Vsubmonitor +p761 +sVvm +p762 +NsVlrt +p763 +F1525814994.487744 +sVda +p764 +V247 +p765 +sg240 +V302 +p766 +sg242 +g698 +sVmisc_u +p767 +g664 +sg245 +g246 +sVmrt +p768 +V10 +p769 +sg249 +Vdivide +p770 +sg251 +g743 +sVmv +p771 +V10 +p772 +sg254 +VOn +p773 +sg256 +V0-600 +p774 +sg258 +Vint +p775 +ssV2-5 +p776 +(dp777 +Vah +p778 +g14 +sVbytary +p779 +NsVal +p780 +g14 +sVvn +p781 +VVoltage: C-A +p782 +sVct +p783 +Vnumber +p784 +sVle +p785 +V16 +p786 +sVgrp +p787 +V600 +p788 +sVla +p789 +g27 +sVchn +p790 +Vvoltage_ca +p791 +sVun +p792 +g233 +sVdn +p793 +Vsubmonitor +p794 +sVvm +p795 +NsVlrt +p796 +F1525815503.6747411 +sVda +p797 +V247 +p798 +sg240 +V303 +p799 +sg242 +g698 +sVmisc_u +p800 +g664 +sg245 +g246 +sVmrt +p801 +V10 +p802 +sg249 +Vdivide +p803 +sg251 +g776 +sVmv +p804 +V10 +p805 +sg254 +VOn +p806 +sg256 +V0-600 +p807 +sg258 +Vint +p808 +ssV2-8 +p809 +(dp810 +Vah +p811 +g14 +sVbytary +p812 +NsVal +p813 +g14 +sVvn +p814 +VPhase Order +p815 +sVct +p816 +Vnumber +p817 +sVle +p818 +V16 +p819 +sVgrp +p820 +V600 +p821 +sVla +p822 +g27 +sVchn +p823 +Vphase_order +p824 +sVun +p825 +g233 +sVdn +p826 +Vsubmonitor +p827 +sVvm +p828 +NsVlrt +p829 +F1525815087.807087 +sVda +p830 +V247 +p831 +sg240 +V306 +p832 +sg242 +g233 +sVmisc_u +p833 +VABC/ACB +p834 +sg245 +g246 +sVmrt +p835 +V10 +p836 +sg249 +Vnone +p837 +sg251 +g809 +sVmv +p838 +g428 +sg254 +VOn +p839 +sg256 +V0-10 +p840 +sg258 +Vint +p841 +ssV2-9 +p842 +(dp843 +Vah +p844 +g14 +sVbytary +p845 +NsVal +p846 +g14 +sVvn +p847 +VVoltage Unbalance +p848 +sVct +p849 +Vnumber +p850 +sVle +p851 +V16 +p852 +sVgrp +p853 +V600 +p854 +sVla +p855 +g27 +sVchn +p856 +Vvoltage_unbalance +p857 +sVun +p858 +g233 +sVdn +p859 +Vsubmonitor +p860 +sVvm +p861 +NsVlrt +p862 +F1525815088.318854 +sVda +p863 +V247 +p864 +sg240 +V307 +p865 +sg242 +g233 +sVmisc_u +p866 +g320 +sg245 +g246 +sVmrt +p867 +V10 +p868 +sg249 +Vdivide +p869 +sg251 +g842 +sVmv +p870 +V10 +p871 +sg254 +VOn +p872 +sg256 +V0-150 +p873 +sg258 +Vint +p874 +ssV2-36 +p875 +(dp876 +Val +p877 +g14 +sVah +p878 +g14 +sVbytary +p879 +NsVvm +p880 +NsVvn +p881 +VAlarm 3 +p882 +sVct +p883 +Vnumber +p884 +sVle +p885 +V16 +p886 +sVgrp +p887 +V600 +p888 +sVla +p889 +g27 +sVchn +p890 +Valarm_3 +p891 +sVun +p892 +g31 +sVdn +p893 +Vsubmonitor +p894 +sVda +p895 +V247 +p896 +sVlrt +p897 +g37 +sg38 +V0-65535 +p898 +sg40 +V206 +p899 +sg42 +g31 +sVmisc_u +p900 +g14 +sg44 +g45 +sVmrt +p901 +V10 +p902 +sg48 +Vnone +p903 +sg50 +g875 +sg51 +VOn +p904 +sVmv +p905 +g37 +sg54 +Vint +p906 +ssV2-40 +p907 +(dp908 +Val +p909 +g14 +sVah +p910 +g14 +sVbytary +p911 +NsVvm +p912 +NsVvn +p913 +VMotor Run Time +p914 +sVct +p915 +Vnumber +p916 +sVle +p917 +V32 +p918 +sVgrp +p919 +V600 +p920 +sVla +p921 +NsVchn +p922 +Vmotor_run_time +p923 +sVun +p924 +g31 +sVdn +p925 +Vsubmonitor +p926 +sVda +p927 +V247 +p928 +sVlrt +p929 +g37 +sg38 +V0-1000000 +p930 +sg40 +V228 +p931 +sg42 +V10 +p932 +sVmisc_u +p933 +VHours +p934 +sg44 +g45 +sVmrt +p935 +V10 +p936 +sg48 +Vnone +p937 +sg50 +g907 +sg51 +VOn +p938 +sVmv +p939 +g37 +sg54 +Vfloat +p940 +ssV2-37 +p941 +(dp942 +Val +p943 +g14 +sVah +p944 +g14 +sVbytary +p945 +NsVvm +p946 +NsVvn +p947 +VAlarm 4 +p948 +sVct +p949 +Vnumber +p950 +sVle +p951 +V16 +p952 +sVgrp +p953 +V600 +p954 +sVla +p955 +g27 +sVchn +p956 +Valarm_4 +p957 +sVun +p958 +g31 +sVdn +p959 +Vsubmonitor +p960 +sVda +p961 +V247 +p962 +sVlrt +p963 +g37 +sg38 +V0-65535 +p964 +sg40 +V207 +p965 +sg42 +g31 +sVmisc_u +p966 +g14 +sg44 +g45 +sVmrt +p967 +V10 +p968 +sg48 +Vnone +p969 +sg50 +g941 +sg51 +VOn +p970 +sVmv +p971 +g37 +sg54 +Vint +p972 +ssV2-14 +p973 +(dp974 +Vah +p975 +g14 +sVbytary +p976 +NsVal +p977 +g14 +sVvn +p978 +VCurrent: B Phase +p979 +sVct +p980 +Vnumber +p981 +sVle +p982 +V16 +p983 +sVgrp +p984 +V600 +p985 +sVla +p986 +g27 +sVchn +p987 +Vcurrent_b +p988 +sVun +p989 +g233 +sVdn +p990 +Vsubmonitor +p991 +sVvm +p992 +NsVlrt +p993 +F1525815088.9524621 +sVda +p994 +V247 +p995 +sg240 +V313 +p996 +sg242 +g233 +sVmisc_u +p997 +g664 +sg245 +g246 +sVmrt +p998 +V10 +p999 +sg249 +Vdivide +p1000 +sg251 +g973 +sVmv +p1001 +V10 +p1002 +sg254 +VOn +p1003 +sg256 +V0-100 +p1004 +sg258 +Vint +p1005 +ssV2-15 +p1006 +(dp1007 +Vah +p1008 +g14 +sVbytary +p1009 +NsVal +p1010 +g14 +sVvn +p1011 +VCurrent: C Phase +p1012 +sVct +p1013 +Vnumber +p1014 +sVle +p1015 +V16 +p1016 +sVgrp +p1017 +V600 +p1018 +sVla +p1019 +g27 +sVchn +p1020 +Vcurrent_c +p1021 +sVun +p1022 +g233 +sVdn +p1023 +Vsubmonitor +p1024 +sVvm +p1025 +NsVlrt +p1026 +F1525815089.436875 +sVda +p1027 +V247 +p1028 +sg240 +V314 +p1029 +sg242 +g233 +sVmisc_u +p1030 +g592 +sg245 +g246 +sVmrt +p1031 +V10 +p1032 +sg249 +Vdivide +p1033 +sg251 +g1006 +sVmv +p1034 +V10 +p1035 +sg254 +VOn +p1036 +sg256 +V0-100 +p1037 +sg258 +Vint +p1038 +ssV2-16 +p1039 +(dp1040 +Vah +p1041 +g14 +sVbytary +p1042 +NsVal +p1043 +g14 +sVvn +p1044 +VCurrent: Ground +p1045 +sVct +p1046 +Vnumber +p1047 +sVle +p1048 +V16 +p1049 +sVgrp +p1050 +V600 +p1051 +sVla +p1052 +g27 +sVchn +p1053 +Vcurrent_ground +p1054 +sVun +p1055 +g233 +sVdn +p1056 +Vsubmonitor +p1057 +sVvm +p1058 +NsVlrt +p1059 +F1525815089.922854 +sVda +p1060 +V247 +p1061 +sg240 +V315 +p1062 +sg242 +g233 +sVmisc_u +p1063 +g592 +sg245 +g246 +sVmrt +p1064 +V10 +p1065 +sg249 +Vdivide +p1066 +sg251 +g1039 +sVmv +p1067 +V10 +p1068 +sg254 +VOn +p1069 +sg256 +V0-100 +p1070 +sg258 +Vint +p1071 +ssV2-17 +p1072 +(dp1073 +Vah +p1074 +g14 +sVbytary +p1075 +NsVal +p1076 +g14 +sVvn +p1077 +VCurrent Unbalance +p1078 +sVct +p1079 +Vnumber +p1080 +sVle +p1081 +V16 +p1082 +sVgrp +p1083 +V600 +p1084 +sVla +p1085 +g27 +sVchn +p1086 +Vcurrent_unbalance +p1087 +sVun +p1088 +g233 +sVdn +p1089 +Vsubmonitor +p1090 +sVvm +p1091 +NsVlrt +p1092 +F1525815090.4537922 +sVda +p1093 +V247 +p1094 +sg240 +V316 +p1095 +sg242 +V0.5 +p1096 +sVmisc_u +p1097 +g320 +sg245 +g246 +sVmrt +p1098 +V10 +p1099 +sg249 +Vdivide +p1100 +sg251 +g1072 +sVmv +p1101 +V10 +p1102 +sg254 +VOn +p1103 +sg256 +V0-150 +p1104 +sg258 +Vint +p1105 +ssV2-10 +p1106 +(dp1107 +Vah +p1108 +g14 +sVbytary +p1109 +NsVal +p1110 +g14 +sVvn +p1111 +VVoltage Min: A-B +p1112 +sVct +p1113 +Vnumber +p1114 +sVle +p1115 +V16 +p1116 +sVgrp +p1117 +V600 +p1118 +sVla +p1119 +g27 +sVchn +p1120 +Vvoltage_ab_min +p1121 +sVun +p1122 +g233 +sVdn +p1123 +Vsubmonitor +p1124 +sVvm +p1125 +NsVlrt +p1126 +F1525815068.0539379 +sVda +p1127 +V247 +p1128 +sg240 +V308 +p1129 +sg242 +g698 +sVmisc_u +p1130 +g664 +sg245 +g246 +sVmrt +p1131 +V10 +p1132 +sg249 +Vdivide +p1133 +sg251 +g1106 +sVmv +p1134 +V10 +p1135 +sg254 +VOn +p1136 +sg256 +V0-600 +p1137 +sg258 +Vint +p1138 +ssV2-11 +p1139 +(dp1140 +Vah +p1141 +g14 +sVbytary +p1142 +NsVal +p1143 +g14 +sVvn +p1144 +VVoltage Min: B-C +p1145 +sVct +p1146 +Vnumber +p1147 +sVle +p1148 +V16 +p1149 +sVgrp +p1150 +V600 +p1151 +sVla +p1152 +g27 +sVchn +p1153 +Vvoltage_bc_min +p1154 +sVun +p1155 +g233 +sVdn +p1156 +Vsubmonitor +p1157 +sVvm +p1158 +NsVlrt +p1159 +F1525815091.4213139 +sVda +p1160 +V247 +p1161 +sg240 +V309 +p1162 +sg242 +g698 +sVmisc_u +p1163 +g664 +sg245 +g246 +sVmrt +p1164 +V10 +p1165 +sg249 +Vdivide +p1166 +sg251 +g1139 +sVmv +p1167 +V10 +p1168 +sg254 +VOn +p1169 +sg256 +V0-600 +p1170 +sg258 +Vint +p1171 +ssV2-12 +p1172 +(dp1173 +Vah +p1174 +g14 +sVbytary +p1175 +NsVal +p1176 +g14 +sVvn +p1177 +VVoltage Min: C-A +p1178 +sVct +p1179 +Vnumber +p1180 +sVle +p1181 +V16 +p1182 +sVgrp +p1183 +V600 +p1184 +sVla +p1185 +g27 +sVchn +p1186 +Vvoltage_ca_min +p1187 +sVun +p1188 +g233 +sVdn +p1189 +Vsubmonitor +p1190 +sVvm +p1191 +NsVlrt +p1192 +F1525815091.9510889 +sVda +p1193 +V247 +p1194 +sg240 +V310 +p1195 +sg242 +g698 +sVmisc_u +p1196 +g664 +sg245 +g246 +sVmrt +p1197 +V10 +p1198 +sg249 +Vdivide +p1199 +sg251 +g1172 +sVmv +p1200 +V10 +p1201 +sg254 +VOn +p1202 +sg256 +V0-600 +p1203 +sg258 +Vint +p1204 +ssV2-13 +p1205 +(dp1206 +Vah +p1207 +g14 +sVbytary +p1208 +NsVal +p1209 +g14 +sVvn +p1210 +VCurrent: A Phase +p1211 +sVct +p1212 +Vnumber +p1213 +sVle +p1214 +V16 +p1215 +sVgrp +p1216 +V600 +p1217 +sVla +p1218 +g27 +sVchn +p1219 +Vcurrent_a +p1220 +sVun +p1221 +g233 +sVdn +p1222 +Vsubmonitor +p1223 +sVvm +p1224 +NsVlrt +p1225 +F1525815092.4871048 +sVda +p1226 +V247 +p1227 +sg240 +V312 +p1228 +sg242 +V0.5 +p1229 +sVmisc_u +p1230 +g592 +sg245 +g246 +sVmrt +p1231 +V10 +p1232 +sg249 +Vdivide +p1233 +sg251 +g1205 +sVmv +p1234 +V10 +p1235 +sg254 +VOn +p1236 +sg256 +V0-100 +p1237 +sg258 +Vint +p1238 +ssV2-38 +p1239 +(dp1240 +Val +p1241 +g14 +sVah +p1242 +g14 +sVbytary +p1243 +NsVvm +p1244 +NsVvn +p1245 +VAlarm 5 +p1246 +sVct +p1247 +Vnumber +p1248 +sVle +p1249 +V16 +p1250 +sVgrp +p1251 +V600 +p1252 +sVla +p1253 +g27 +sVchn +p1254 +Valarm_5 +p1255 +sVun +p1256 +g31 +sVdn +p1257 +Vsubmonitor +p1258 +sVda +p1259 +V247 +p1260 +sVlrt +p1261 +g37 +sg38 +V0-65535 +p1262 +sg40 +V208 +p1263 +sg42 +g31 +sVmisc_u +p1264 +g14 +sg44 +g45 +sVmrt +p1265 +V10 +p1266 +sg48 +Vnone +p1267 +sg50 +g1239 +sg51 +VOn +p1268 +sVmv +p1269 +g37 +sg54 +Vint +p1270 +ssV2-39 +p1271 +(dp1272 +Val +p1273 +g14 +sVah +p1274 +g14 +sVbytary +p1275 +NsVvm +p1276 +NsVvn +p1277 +VV1/V2 Status +p1278 +sVct +p1279 +Vnumber +p1280 +sVle +p1281 +V16 +p1282 +sVgrp +p1283 +V600 +p1284 +sVla +p1285 +g27 +sVchn +p1286 +Vterminal_v1_v2 +p1287 +sVun +p1288 +g31 +sVdn +p1289 +Vsubmonitor +p1290 +sVda +p1291 +V247 +p1292 +sVlrt +p1293 +g37 +sg38 +V0-65535 +p1294 +sg40 +V214 +p1295 +sg42 +g31 +sVmisc_u +p1296 +g14 +sg44 +g45 +sVmrt +p1297 +V10 +p1298 +sg48 +Vnone +p1299 +sg50 +g1271 +sg51 +VOn +p1300 +sVmv +p1301 +g37 +sg54 +Vint +p1302 +ssV2-18 +p1303 +(dp1304 +Vah +p1305 +g14 +sVbytary +p1306 +NsVal +p1307 +g14 +sVvn +p1308 +VCurrent Peak +p1309 +sVct +p1310 +Vnumber +p1311 +sVle +p1312 +V16 +p1313 +sVgrp +p1314 +V600 +p1315 +sVla +p1316 +g27 +sVchn +p1317 +Vcurrent_peak +p1318 +sVun +p1319 +g233 +sVdn +p1320 +Vsubmonitor +p1321 +sVvm +p1322 +NsVlrt +p1323 +F1525815093.2170552 +sVda +p1324 +V247 +p1325 +sg240 +V317 +p1326 +sg242 +g233 +sVmisc_u +p1327 +g592 +sg245 +g246 +sVmrt +p1328 +V10 +p1329 +sg249 +Vdivide +p1330 +sg251 +g1303 +sVmv +p1331 +V10 +p1332 +sg254 +VOn +p1333 +sg256 +V0-150 +p1334 +sg258 +Vint +p1335 +ssV2-19 +p1336 +(dp1337 +Vah +p1338 +g14 +sVbytary +p1339 +NsVal +p1340 +g14 +sVvn +p1341 +VPower: kW +p1342 +sVct +p1343 +Vnumber +p1344 +sVle +p1345 +V16 +p1346 +sVgrp +p1347 +V600 +p1348 +sVla +p1349 +g27 +sVchn +p1350 +Vpower_kw +p1351 +sVun +p1352 +g233 +sVdn +p1353 +Vsubmonitor +p1354 +sVvm +p1355 +NsVlrt +p1356 +F1525815093.7597689 +sVda +p1357 +V247 +p1358 +sg240 +V318 +p1359 +sg242 +g456 +sVmisc_u +p1360 +VkW +p1361 +sg245 +g246 +sVmrt +p1362 +V10 +p1363 +sg249 +Vdivide +p1364 +sg251 +g1336 +sVmv +p1365 +V10 +p1366 +sg254 +VOn +p1367 +sg256 +V0-65535 +p1368 +sg258 +Vint +p1369 +ssssS'f' +p1370 +VOff +p1371 +sS'p' +p1372 +g14 +sS's' +p1373 +V2 +p1374 +ssS'2' +p1375 +(dp1376 +g3 +VM1-485 +p1377 +sg5 +V9600 +p1378 +sg7 +(dp1379 +sg1370 +VOff +p1380 +sg1372 +VNone +p1381 +sg1373 +g31 +ss. \ No newline at end of file diff --git a/submonitor/python-driver/persistence.py b/submonitor/python-driver/persistence.py new file mode 100644 index 0000000..8c8703f --- /dev/null +++ b/submonitor/python-driver/persistence.py @@ -0,0 +1,21 @@ +"""Data persistance functions.""" +# if more advanced persistence is needed, use a sqlite database +import json + + +def load(filename="persist.json"): + """Load persisted settings from the specified file.""" + try: + with open(filename, 'r') as persist_file: + return json.load(persist_file) + except Exception: + return False + + +def store(persist_obj, filename="persist.json"): + """Store the persisting settings into the specified file.""" + try: + with open(filename, 'w') as persist_file: + return json.dump(persist_obj, persist_file, indent=4) + except Exception: + return False diff --git a/submonitor/python-driver/submonitor.py b/submonitor/python-driver/submonitor.py new file mode 100644 index 0000000..4d891a5 --- /dev/null +++ b/submonitor/python-driver/submonitor.py @@ -0,0 +1,62 @@ +"""Driver for submonitor""" + +import threading +import sys +from device_base import deviceBase +import time +import logging + +_ = None + +# LOGGING SETUP +from logging.handlers import RotatingFileHandler + +log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s') +logFile = './submonitor.log' +my_handler = RotatingFileHandler(logFile, mode='a', maxBytes=500*1024, backupCount=2, encoding=None, delay=0) +my_handler.setFormatter(log_formatter) +my_handler.setLevel(logging.INFO) +logger = logging.getLogger('submonitor') +logger.setLevel(logging.INFO) +logger.addHandler(my_handler) + +console_out = logging.StreamHandler(sys.stdout) +console_out.setFormatter(log_formatter) +logger.addHandler(console_out) + +logger.info("submonitor startup") + + +class start(threading.Thread, deviceBase): + """Start class required by Meshify.""" + + def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None): + """Initialize the driver.""" + threading.Thread.__init__(self) + deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes) + + self.daemon = True + self.version = "2" + self.finished = threading.Event() + self.forceSend = False + threading.Thread.start(self) + + # this is a required function for all drivers, its goal is to upload some piece of data + # about your device so it can be seen on the web + def register(self): + """Register the driver.""" + # self.sendtodb("log", "BOOM! Booted.", 0) + pass + + def run(self): + """Actually run the driver.""" + wait_sec = 60 + for i in range(0, wait_sec): + print("submonitor driver will start in {} seconds".format(wait_sec - i)) + time.sleep(1) + logger.info("BOOM! Starting submonitor driver...") + + while True: + time.sleep(15) + print("submonitor driver still alive...") + diff --git a/submonitor/python-driver/utilities.py b/submonitor/python-driver/utilities.py new file mode 100644 index 0000000..58c7ab0 --- /dev/null +++ b/submonitor/python-driver/utilities.py @@ -0,0 +1,51 @@ +"""Utility functions for the driver.""" +import socket +import struct + + +def get_public_ip_address(): + """Find the public IP Address of the host device.""" + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + 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:] + sign = 1.0 + if int(bin_rep[0]) == 1: + sign = -1.0 + exponent = float(int(bin_rep[1:6], 2)) + fraction = float(int(bin_rep[6:17], 2)) + + if exponent == float(0b00000): + return sign * 2 ** -14 * fraction / (2.0 ** 10.0) + elif exponent == float(0b11111): + if fraction == 0: + return sign * float("inf") + else: + return float("NaN") + else: + frac_part = 1.0 + fraction / (2.0 ** 10.0) + return sign * (2 ** (exponent - 15)) * frac_part + + +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.""" + return (temp_f - 32.0) * (5.0/9.0) + + +def degc_to_degf(temp_c): + """Convert deg C to deg F.""" + return temp_c * 1.8 + 32.0