Added Folders

Add all the driver folders
This commit is contained in:
2019-12-13 12:15:30 -06:00
parent 7ea92c19f6
commit 632dcdb3e8
226 changed files with 54771 additions and 0 deletions

282
dhsensor/Channel.py Normal file
View File

@@ -0,0 +1,282 @@
"""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):
"""Read a tag from the PLC."""
c = ClxDriver()
try:
if c.open(addr):
try:
v = c.read_tag(tag)
return v
except DataError:
c.close()
print("Data Error during readTag({}, {})".format(addr, tag))
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):
"""Read an array from the PLC."""
c = ClxDriver()
if c.open(addr):
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):
"""Write a tag value to the PLC."""
c = ClxDriver()
if c.open(addr):
try:
cv = c.read_tag(tag)
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):
"""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
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

47
dhsensor/Maps.py Normal file
View File

@@ -0,0 +1,47 @@
"""Holds map values for prostarsolar."""
def charge_state(inp_state):
"""Map function for charge state."""
states = {
0: "Start",
1: "Night Check",
2: "Disconnect",
3: "Night",
4: "Fault",
5: "Bulk",
6: "Absorption",
7: "Float",
8: "Equalize"
}
if inp_state in range(0,9):
return states[inp_state]
else:
return inp_state
def array_faults(inp_array_faults):
"""Form a string for the array_faults."""
fault_string = ""
faults = {
0: "Overcurrent Phase 1",
1: "FETs Shorted",
2: "Software Bug",
3: "Battery HVD (High Voltage Disconnect)",
4: "Array HVD (High Voltage Disconnect)",
5: "EEPROM Setting Edit (reset required)",
6: "RTS Shorted",
7: "RTS was valid now disconnected",
8: "Local temp. sensor failed",
9: "Battery LVD (Low Voltage Disconect)",
10: "DIP Switch Changed (excl. DIP 8)",
11: "Processor Supply Fault"
}
bit_string = ("0" * 16 + "{0:b}".format(inp_array_faults))[-16:]
for i in range(0, 12):
if int(bit_string[i]) == 1:
fault_string += faults[i] + ", "
if fault_string:
return fault_string[:-2]
else:
return "None"

12
dhsensor/config.txt Normal file
View File

@@ -0,0 +1,12 @@
{
"files": {
"file3": "persistence.py",
"file2": "utilities.py",
"file1": "dhsensor.py",
"file4": "modbusMap.p"
},
"deviceName": "dhsensor",
"driverId": "0170",
"releaseVersion": "1",
"driverFileName": "dhsensor.py"
}

84
dhsensor/dhsensor.py Normal file
View File

@@ -0,0 +1,84 @@
"""Driver for dhsensor."""
import threading
from device_base import deviceBase
import persistence
from utilities import get_public_ip_address
import time
_ = None
# GLOBAL VARIABLES
WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending the watchdog status
PLC_IP_ADDRESS = "192.168.1.10"
# PERSISTENCE FILE
persist = persistence.load()
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 = "1"
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."""
global persist
wait_sec = 60
for i in range(0, wait_sec):
print("dhsensor driver will start in {} seconds".format(wait_sec - i))
time.sleep(1)
print("BOOM! Starting dhsensor driver...")
self.nodes["dhsensor_0199"] = self
public_ip_address = get_public_ip_address()
self.sendtodbDev(1, 'public_ip_address', public_ip_address, 0, 'dhsensor')
send_loops = 0
watchdog_loops = 0
watchdog_check_after = 5000
while True:
if self.forceSend:
print "FORCE SEND: TRUE"
print("dhsensor driver still alive...")
if self.forceSend:
if send_loops > 2:
print("Turning off forceSend")
self.forceSend = False
send_loops = 0
else:
send_loops += 1
watchdog_loops += 1
if (watchdog_loops >= watchdog_check_after):
test_public_ip = get_public_ip_address()
if not test_public_ip == public_ip_address:
self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'dhsensor')
public_ip_address = test_public_ip
watchdog_loops = 0
time.sleep(10)
def dhsensor_sync(self, name, value):
"""Sync all data from the driver."""
self.forceSend = True
# self.sendtodb("log", "synced", 0)
return True

578
dhsensor/modbusMap.p Normal file
View File

@@ -0,0 +1,578 @@
(dp0
S'1'
p1
(dp2
S'c'
p3
VM1-485
p4
sS'b'
p5
V38400
p6
sS'addresses'
p7
(dp8
V1
p9
(dp10
V2-2
p11
(dp12
Vah
p13
V90
p14
sVbytary
p15
NsVal
p16
V4
p17
sVvn
p18
VIntake Pressure
p19
sVct
p20
Vnumber
p21
sVle
p22
V16
p23
sVgrp
p24
V3600
p25
sVla
p26
I0
sVchn
p27
Vintake_pressure
p28
sVun
p29
V01
p30
sVdn
p31
Vdhsensor
p32
sVda
p33
g9
sVlrt
p34
F1568755102.8790879
sVr
p35
V0-100
p36
sVa
p37
g9
sVc
p38
g9
sVmisc_u
p39
VPSI
p40
sVf
p41
V3
p42
sVmrt
p43
V20
p44
sVm
p45
Vnone
p46
sS'm1ch'
p47
g11
sVs
p48
VOn
p49
sVmv
p50
V0
p51
sVt
p52
Vint
p53
sVvm
p54
NssV2-3
p55
(dp56
Vah
p57
V90
p58
sVbytary
p59
NsVal
p60
V5
p61
sVvn
p62
VDischarge Pressure
p63
sVct
p64
Vnumber
p65
sVle
p66
V16
p67
sVgrp
p68
V3600
p69
sVla
p70
I0
sVchn
p71
Vdischarge_pressure
p72
sVun
p73
V01
p74
sVdn
p75
Vdhsensor
p76
sVda
p77
g9
sVlrt
p78
F1568755103.3660561
sg35
V0-100
p79
sg37
g61
sg38
g9
sVmisc_u
p80
VPSI
p81
sg41
g42
sVmrt
p82
V20
p83
sg45
Vnone
p84
sg47
g55
sg48
VOn
p85
sVmv
p86
g51
sg52
Vint
p87
sVvm
p88
NssV2-1
p89
(dp90
Vah
p91
V
p92
sVbytary
p93
NsVal
p94
g92
sVvn
p95
VIntake Temperature
p96
sVct
p97
Vnumber
p98
sVle
p99
V16
p100
sVgrp
p101
V3600
p102
sVla
p103
g92
sVchn
p104
Vintake_temperature
p105
sVun
p106
V01
p107
sVdn
p108
Vdhsensor
p109
sVda
p110
V1
p111
sVlrt
p112
F1568753044.747895
sVr
p113
V0-100
p114
sVa
p115
V0
p116
sVc
p117
g111
sVmisc_u
p118
VF
p119
sVf
p120
V3
p121
sVmrt
p122
V20
p123
sVm
p124
Vnone
p125
sVm1ch
p126
g89
sVs
p127
VOn
p128
sVmv
p129
g116
sVt
p130
Vint
p131
sVvm
p132
NssV2-6
p133
(dp134
Vah
p135
g92
sVbytary
p136
NsVal
p137
g92
sVvn
p138
VDown Hole Level
p139
sVct
p140
Vnumber
p141
sVle
p142
V16
p143
sVgrp
p144
V3600
p145
sVla
p146
g92
sVchn
p147
Vdh_level
p148
sg113
V0-1023
p149
sVdn
p150
Vdhsensor
p151
sVda
p152
g111
sVlrt
p153
F1568753045.237281
sg115
g111
sg117
g111
sVmisc_u
p154
VFt
p155
sg120
g121
sVmrt
p156
V20
p157
sg124
Vfunction
p158
sVm1ch
p159
g133
sVmv
p160
Vx * (60 / 1023) + (60 - 1023 * (60/1023))
p161
sg127
VOn
p162
sVun
p163
V01
p164
sg130
Vint
p165
sVvm
p166
NssV2-4
p167
(dp168
Vah
p169
g92
sVbytary
p170
NsVal
p171
g92
sVvn
p172
VDischarge Temperature
p173
sVct
p174
Vnumber
p175
sVle
p176
V16
p177
sVgrp
p178
V3600
p179
sVla
p180
I0
sVchn
p181
Vdischarge_temperature
p182
sVun
p183
V01
p184
sVdn
p185
Vdhsensor
p186
sVda
p187
g9
sVlrt
p188
F1568755096.304796
sg35
V0-100
p189
sg37
V6
p190
sg38
g9
sVmisc_u
p191
VF
p192
sg41
g42
sVmrt
p193
V20
p194
sg45
Vnone
p195
sg47
g167
sg48
VOn
p196
sVmv
p197
g51
sg52
Vint
p198
sVvm
p199
NssV2-5
p200
(dp201
Vah
p202
g92
sVbytary
p203
NsVal
p204
g92
sVvn
p205
VD/H Status
p206
sVct
p207
Vnumber
p208
sVle
p209
V16
p210
sVgrp
p211
V3600
p212
sVla
p213
I2
sVchn
p214
Vdh_status
p215
sVun
p216
V01
p217
sVdn
p218
Vdhsensor
p219
sVda
p220
g9
sVlrt
p221
F1568755097.231012
sg35
g92
sg37
V97
p222
sg38
g9
sVmisc_u
p223
g92
sg41
g42
sVmrt
p224
g61
sg45
Vnone
p225
sg47
g200
sg48
VOn
p226
sVmv
p227
g51
sg52
Vint
p228
sVvm
p229
(dp230
g9
VConnecting
p231
sg51
VOK
p232
sg42
VShorted
p233
sV2
p234
VOpen Circuit
p235
sg17
VCannot Decode
p236
sssssS'f'
p237
VOff
p238
sS'p'
p239
g92
sS's'
p240
g111
ssS'2'
p241
(dp242
g3
VM1-485
p243
sg5
V9600
p244
sg7
(dp245
sg237
VOff
p246
sg239
VNone
p247
sg240
g111
ss.

21
dhsensor/persistence.py Normal file
View File

@@ -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)
except Exception:
return False

53
dhsensor/utilities.py Normal file
View File

@@ -0,0 +1,53 @@
"""Utility functions for the driver."""
import socket
def get_public_ip_address():
"""Find the public IP Address of the host device."""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
except:
return "Could not connect to the Internet"
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 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
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