updates to thunderbird report and meshify drivers
This commit is contained in:
13
Code Snippets/deviceList Template.txt
Normal file
13
Code Snippets/deviceList Template.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
{'mainHP': 'https://hp-drivers.s3-us-west-2.amazonaws.com/mainMeshify/piflow/','PiFlow': 'https://s3.amazonaws.com/pocloud-drivers/piflow/'}
|
||||
|
||||
Test Device
|
||||
B8:27:EB:D6:9E:0D
|
||||
|
||||
Wilkison 39 WS 2-2
|
||||
B8:27:EB:96:A0:2D
|
||||
|
||||
{'mainHP': 'https://hp-thingsboard.s3.us-east-1.amazonaws.com/mainHPRPI/','PiFlow': 'https://hp-thingsboard.s3.us-east-1.amazonaws.com/piflow/'}
|
||||
|
||||
|
||||
|
||||
{"mainHP": "https://hp-thingsboard.s3.us-east-1.amazonaws.com/mainHPRPI/","PiFlow": "https://hp-thingsboard.s3.us-east-1.amazonaws.com/piflow/"}
|
||||
@@ -5,7 +5,7 @@ codeuri = "/Users/nico/Documents/GitHub/ThingsBoard/EKKO Reports/thunderbirdfs-d
|
||||
runtime = "python3.9"
|
||||
architecture = "x86_64"
|
||||
handler = "thunderbirdfsreport.lambda_handler"
|
||||
source_hash = "6c4b8d3b845be890fff876b4331c5d3b90962571c77b17c0b9ab45f47ea452f8"
|
||||
source_hash = "6f17c158c10bfe2991363a32538aafe8f3fd8e91954f67bbab36888d81abdfbf"
|
||||
manifest_hash = ""
|
||||
packagetype = "Zip"
|
||||
functions = ["ThunderbirdFSReport"]
|
||||
|
||||
@@ -296,6 +296,10 @@ def lambda_handler(event, context):
|
||||
"Bruce@enxl.us",
|
||||
"Joshua.Fine@fineelectricalservices2018.com"
|
||||
]
|
||||
|
||||
emails = [
|
||||
"tquiet@henry-pump.com"
|
||||
]
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = "Thunderbird Field Services"
|
||||
msg['From'] = 'alerts@henry-pump.com'
|
||||
|
||||
@@ -296,6 +296,7 @@ def lambda_handler(event, context):
|
||||
"Bruce@enxl.us",
|
||||
"Joshua.Fine@fineelectricalservices2018.com"
|
||||
]
|
||||
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = "Thunderbird Field Services"
|
||||
msg['From'] = 'alerts@henry-pump.com'
|
||||
|
||||
20
ThingsBoard Client/controllers.py
Normal file
20
ThingsBoard Client/controllers.py
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
class ModbusRTU:
|
||||
def __init__(self, address=1, baud=9600, bits=8, parity="n", stopbits=1, instrument="/dev/ttyS0"):
|
||||
self.address = address
|
||||
self.baud = baud
|
||||
self.bits = bits
|
||||
self.parity = parity
|
||||
self.stopbits = stopbits
|
||||
self.instrument = instrument
|
||||
|
||||
def read():
|
||||
pass
|
||||
|
||||
def write():
|
||||
pass
|
||||
def ModbusRTURead():
|
||||
return "Modbus Read"
|
||||
|
||||
def EthernetIPRead():
|
||||
return "EthernetIP Read"
|
||||
122
ThingsBoard Client/main.py
Normal file
122
ThingsBoard Client/main.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import logging.handlers
|
||||
import time
|
||||
import os
|
||||
import json
|
||||
from controllers import ModbusRTURead, EthernetIPRead
|
||||
from tb_gateway_mqtt import TBDeviceMqttClient, RateLimit
|
||||
def parse_config(config_file):
|
||||
"""Parses the configuration file and returns a dictionary."""
|
||||
|
||||
with open(config_file, 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
return config
|
||||
|
||||
CONFIG_DATA = parse_config('device_supervisor.cfg')
|
||||
THINGSBOARD_SERVER = CONFIG_DATA['clouds'][0]['args']['host']
|
||||
ACCESS_TOKEN = CONFIG_DATA['clouds'][0]['args']['username']
|
||||
# Convert string level to logging level constant
|
||||
logging_levels = {
|
||||
"DEBUG": logging.DEBUG,
|
||||
"INFO": logging.INFO,
|
||||
"WARNING": logging.WARNING,
|
||||
"ERROR": logging.ERROR,
|
||||
"CRITICAL": logging.CRITICAL
|
||||
}
|
||||
log_level_int = logging_levels.get(CONFIG_DATA['misc']['logLvl'], logging.INFO)
|
||||
logging.basicConfig(filename='main.log',
|
||||
level=log_level_int,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
client = None
|
||||
|
||||
# default blinking period
|
||||
period = 1.0
|
||||
|
||||
|
||||
|
||||
# callback function that will call when we will change value of our Shared Attribute
|
||||
|
||||
|
||||
def attribute_callback(result, _):
|
||||
logging.info(result)
|
||||
# make sure that you paste YOUR shared attribute name
|
||||
period = result.get('blinkingPeriod', 1.0)
|
||||
|
||||
# callback function that will call when we will send RPC
|
||||
|
||||
|
||||
def rpc_callback(id, request_body):
|
||||
# request body contains method and other parameters
|
||||
logging.info(request_body)
|
||||
method = request_body.get('method')
|
||||
if method == 'getTelemetry':
|
||||
attributes, telemetry = get_data()
|
||||
client.send_attributes(attributes)
|
||||
client.send_telemetry(telemetry)
|
||||
else:
|
||||
logging.error('Unknown method: ' + method)
|
||||
|
||||
|
||||
def get_data(controllers=[], measures=[], groups=[]):
|
||||
for measure in measures:
|
||||
logging.info(f"Controller: {measure['ctrlName']}, Measure: {measure['name']}, Group: {measure['group']}")
|
||||
if controllers[measure['ctrlName']]['protocol'] == "Modbus-RTU":
|
||||
logging.info(ModbusRTURead())
|
||||
elif controllers[measure['ctrlName']]['protocol'] == "EtherNet/IP":
|
||||
logging.info(EthernetIPRead())
|
||||
attributes = {
|
||||
"latestReportTime": int(round(time.time() * 1000))
|
||||
}
|
||||
telemetry = {
|
||||
"test": "test"
|
||||
}
|
||||
logging.info(attributes, telemetry)
|
||||
return attributes, telemetry
|
||||
|
||||
# request attribute callback
|
||||
|
||||
|
||||
def sync_state(result, exception=None):
|
||||
global period
|
||||
if exception is not None:
|
||||
logging.info("Exception: " + str(exception))
|
||||
else:
|
||||
period = result.get('shared', {'blinkingPeriod': 1.0})[
|
||||
'blinkingPeriod']
|
||||
|
||||
def rearrange_config(config):
|
||||
out = {}
|
||||
for c in config:
|
||||
out[c['name']] = c
|
||||
return out
|
||||
def main():
|
||||
global client
|
||||
# Example Usage:
|
||||
|
||||
controllers = rearrange_config(CONFIG_DATA['controllers'])
|
||||
measures = CONFIG_DATA['measures']
|
||||
groups = rearrange_config(CONFIG_DATA['groups'])
|
||||
logging.info(controllers)
|
||||
client = TBDeviceMqttClient(THINGSBOARD_SERVER, username=ACCESS_TOKEN, rate_limit="10:1,60:60,")
|
||||
client.connect()
|
||||
client.request_attributes(
|
||||
shared_keys=['blinkingPeriod'], callback=sync_state)
|
||||
|
||||
# now attribute_callback will process shared attribute request from server
|
||||
sub_id_1 = client.subscribe_to_attribute(
|
||||
"blinkingPeriod", attribute_callback)
|
||||
sub_id_2 = client.subscribe_to_all_attributes(attribute_callback)
|
||||
|
||||
# now rpc_callback will process rpc requests from server
|
||||
client.set_server_side_rpc_request_handler(rpc_callback)
|
||||
|
||||
while not client.stopped:
|
||||
attributes, telemetry = get_data(controllers=controllers, measures=measures, groups=groups)
|
||||
client.send_attributes(attributes)
|
||||
client.send_telemetry({"ts": int(round(time.time() * 1000)), "values": telemetry})
|
||||
time.sleep(60)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
245
Thingsboard Gateway/piflow.json
Normal file
245
Thingsboard Gateway/piflow.json
Normal file
@@ -0,0 +1,245 @@
|
||||
{
|
||||
"master": {
|
||||
"slaves": [
|
||||
{
|
||||
"method": "rtu",
|
||||
"baudrate": 9600,
|
||||
"stopbits": 1,
|
||||
"bytesize": 8,
|
||||
"parity": "N",
|
||||
"strict": true,
|
||||
"unitId": 247,
|
||||
"deviceName": "Test Flowmeter",
|
||||
"deviceType": "piflow",
|
||||
"timeout": 35,
|
||||
"byteOrder": "LITTLE",
|
||||
"wordOrder": "LITTLE",
|
||||
"retries": true,
|
||||
"retryOnEmpty": true,
|
||||
"retryOnInvalid": true,
|
||||
"pollPeriod": 5000,
|
||||
"connectAttemptTimeMs": 5000,
|
||||
"connectAttemptCount": 5,
|
||||
"waitAfterFailedAttemptsMs": 300000,
|
||||
"reportStrategy": {
|
||||
"type": "ON_REPORT_PERIOD",
|
||||
"reportPeriod": 600000
|
||||
},
|
||||
"type": "serial",
|
||||
"attributes": [
|
||||
{
|
||||
"tag": "flow_unit",
|
||||
"type": "16int",
|
||||
"address": 2103,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_1_unit",
|
||||
"type": "16int",
|
||||
"address": 4604,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_2_unit",
|
||||
"type": "16int",
|
||||
"address": 4605,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_3_unit",
|
||||
"type": "16int",
|
||||
"address": 4606,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "byte_order",
|
||||
"type": "16int",
|
||||
"address": 4915,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "device_name",
|
||||
"type": "string",
|
||||
"address": 7238,
|
||||
"objectsCount": 14,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "serial_number",
|
||||
"type": "string",
|
||||
"address": 7003,
|
||||
"objectsCount": 12,
|
||||
"functionCode": 4
|
||||
}
|
||||
],
|
||||
"timeseries": [
|
||||
{
|
||||
"tag": "flowrate",
|
||||
"type": "32float",
|
||||
"address": 3874,
|
||||
"objectsCount": 2,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_1",
|
||||
"type": "32float",
|
||||
"address": 2610,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_1_overflow",
|
||||
"type": "32float",
|
||||
"address": 2612,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_2",
|
||||
"type": "32float",
|
||||
"address": 2810,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_2_overflow",
|
||||
"type": "32float",
|
||||
"address": 2812,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_3",
|
||||
"type": "32float",
|
||||
"address": 3010,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
},
|
||||
{
|
||||
"tag": "totalizer_3_overflow",
|
||||
"type": "32float",
|
||||
"address": 3012,
|
||||
"objectsCount": 1,
|
||||
"functionCode": 4
|
||||
}
|
||||
],
|
||||
"attributeUpdates": [
|
||||
{
|
||||
"tag": "shared_attribute_write",
|
||||
"type": "32int",
|
||||
"functionCode": 6,
|
||||
"objectsCount": 2,
|
||||
"address": 29
|
||||
}
|
||||
],
|
||||
"rpc": [
|
||||
{
|
||||
"tag": "setValue",
|
||||
"type": "bits",
|
||||
"functionCode": 5,
|
||||
"objectsCount": 1,
|
||||
"address": 31
|
||||
},
|
||||
{
|
||||
"tag": "getValue",
|
||||
"type": "bits",
|
||||
"functionCode": 1,
|
||||
"objectsCount": 1,
|
||||
"address": 31
|
||||
},
|
||||
{
|
||||
"tag": "resetTotalizers",
|
||||
"type": "bits",
|
||||
"functionCode": 1,
|
||||
"objectsCount": 1,
|
||||
"address": 2609
|
||||
}
|
||||
],
|
||||
"port": "/dev/ttyS0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"slave": {
|
||||
"type": "tcp",
|
||||
"host": "127.0.0.1",
|
||||
"port": 5026,
|
||||
"method": "socket",
|
||||
"deviceName": "Modbus Slave Example",
|
||||
"deviceType": "default",
|
||||
"pollPeriod": 5000,
|
||||
"sendDataToThingsBoard": false,
|
||||
"byteOrder": "LITTLE",
|
||||
"wordOrder": "LITTLE",
|
||||
"unitId": 0,
|
||||
"values": {
|
||||
"holding_registers": {
|
||||
"attributes": [
|
||||
{
|
||||
"address": 1,
|
||||
"type": "string",
|
||||
"tag": "sm",
|
||||
"objectsCount": 1,
|
||||
"value": "ON"
|
||||
}
|
||||
],
|
||||
"timeseries": [
|
||||
{
|
||||
"address": 2,
|
||||
"type": "8int",
|
||||
"tag": "smm",
|
||||
"objectsCount": 1,
|
||||
"value": "12334"
|
||||
}
|
||||
],
|
||||
"attributeUpdates": [
|
||||
{
|
||||
"tag": "shared_attribute_write",
|
||||
"type": "32int",
|
||||
"functionCode": 6,
|
||||
"objectsCount": 2,
|
||||
"address": 29,
|
||||
"value": 1243
|
||||
}
|
||||
],
|
||||
"rpc": [
|
||||
{
|
||||
"tag": "setValue",
|
||||
"type": "bits",
|
||||
"functionCode": 5,
|
||||
"objectsCount": 1,
|
||||
"address": 31,
|
||||
"value": 22
|
||||
}
|
||||
]
|
||||
},
|
||||
"coils_initializer": {
|
||||
"attributes": [
|
||||
{
|
||||
"address": 5,
|
||||
"type": "8int",
|
||||
"tag": "coil",
|
||||
"objectsCount": 1,
|
||||
"value": 0
|
||||
}
|
||||
],
|
||||
"timeseries": [],
|
||||
"attributeUpdates": [],
|
||||
"rpc": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"logLevel": "INFO",
|
||||
"name": "test",
|
||||
"enableRemoteLogging": false,
|
||||
"id": "ce7103fa-159f-4bdf-bcdc-137a74a604ef",
|
||||
"configVersion": "3.5.3.1",
|
||||
"reportStrategy": {
|
||||
"type": "ON_REPORT_PERIOD",
|
||||
"reportPeriod": 60000
|
||||
}
|
||||
}
|
||||
293
deviceMap.json
Normal file
293
deviceMap.json
Normal file
@@ -0,0 +1,293 @@
|
||||
{
|
||||
"C4:93:00:0E:D5:03": "Nail Ranch 37 SR 2-3",
|
||||
"C4:93:00:0C:68:36": "Wrage 21 SR 2-2",
|
||||
"C4:93:00:08:D0:11": "Wrage 28 SR 2-2",
|
||||
"B8:27:EB:46:8D:7D": "Free 40 WS 2-2",
|
||||
"B8:27:EB:78:03:88": "Wilkinson 1 WS 1-9",
|
||||
"B8:27:EB:86:B6:DC": "Wilkinson 1 WS 1-10B",
|
||||
"B8:27:EB:06:B1:94": "Wilkinson 39 WS 1-3",
|
||||
"B8:27:EB:02:2F:F0": "Wilkinson 4 WS 1-10",
|
||||
"B8:27:EB:C1:AC:F5": "Horton 34 WS 10-5",
|
||||
"C4:93:00:0A:89:F5": "Bowling WW 4-1",
|
||||
"C4:93:00:08:D0:65": "Banay WW 7-1",
|
||||
"C4:93:00:0E:E9:C1": "Banay WW 5-1",
|
||||
"C4:93:00:09:51:CE": "Bowling WW 37-1",
|
||||
"C4:93:00:0C:68:57": "Banay WW 504",
|
||||
"C4:93:00:0D:F2:68": "Banay WW 18 #4",
|
||||
"C4:93:00:0D:BB:48": "Banay WW 18 #9",
|
||||
"00:00:01:00:00:05": "Windham 108-1",
|
||||
"00:00:01:00:00:07": "Windham 108-3",
|
||||
"C4:93:00:08:D4:49": "Wrage Ranch 32 SR 1-1",
|
||||
"B8:27:EB:68:43:70": "LimeQuest 5 WS 10-10",
|
||||
"00:00:00:00:00:02": "Florence WW #2",
|
||||
"00:00:00:00:00:03": "Florence WW #1",
|
||||
"00:00:00:00:00:11": "Madelyn Kate #3 WW",
|
||||
"00:00:00:00:00:14": "Jessica WW #3",
|
||||
"00:00:01:00:00:01": "Windham 108-7",
|
||||
"00:00:01:00:00:02": "Windham 108-6",
|
||||
"00:00:01:00:00:03": "Windham 108-5",
|
||||
"00:00:01:00:00:04": "Windham 107-1",
|
||||
"00:00:01:00:00:08": "Windham 107-2",
|
||||
"00:00:01:00:00:09": "Windham 108-8",
|
||||
"00:00:01:00:00:10": "Windham 108-10",
|
||||
"00:00:01:00:00:11": "Windham 108-2",
|
||||
"00:00:01:00:00:12": "Windham 108-9",
|
||||
"00:00:00:00:00:18": "Jessica WW #7",
|
||||
"C4:93:00:0D:F1:6C": "Faudree Frac Pit Pump #1",
|
||||
"C4:93:00:0D:F2:8C": "Faudree Frac Pit Pump #2",
|
||||
"C4:93:00:03:AF:34": "Wilkinson Ranch 34 SR 2-2",
|
||||
"C4:93:00:05:DD:A2": "Nail Ranch 2 SR 3-3",
|
||||
"C4:93:00:03:54:C5": "Nail Ranch 38 SR 2-3",
|
||||
"C4:93:00:03:69:C8": "Nail Ranch 25 SR 2-1",
|
||||
"C4:93:00:05:DD:ED": "Nail Ranch 28 SR 3-3",
|
||||
"C4:93:00:03:56:7B": "Nail Ranch 38 SR 1-3",
|
||||
"C4:93:00:03:6B:12": "Nail Ranch 3 SR 3-2",
|
||||
"C4:93:00:03:7F:B2": "Nail Ranch 28 SR 2-2",
|
||||
"C4:93:00:05:85:1F": "Nail Ranch 28 SR 1-1",
|
||||
"C4:93:00:03:6B:2D": "Guitar 22 SR 3-3",
|
||||
"C4:93:00:0C:D2:29": "Wilkinson Ranch 33 SR 2-2",
|
||||
"C4:93:00:0C:67:AF": "Wilkinson Ranch 35 SR 1-1",
|
||||
"C4:93:00:0C:AA:75": "Wilkinson Ranch 1 SR 2-2",
|
||||
"C4:93:00:0D:F3:55": "Limequest Transfer Lite",
|
||||
"C4:93:00:0D:F2:5C": "S. Wilkinson Transfer Lite",
|
||||
"C4:93:00:0D:F2:8F": "Nail Ranch 2 SR 2-2",
|
||||
"C4:93:00:0D:F0:CA": "Horton Transfer Lite",
|
||||
"C4:93:00:0D:F2:B0": "South Wilkinson Transfer #2",
|
||||
"B8:27:EB:16:F0:64": "Wilkinson 39 WS 1-5",
|
||||
"B8:27:EB:D8:64:A6": "Wilkinson 39 WS 1-4",
|
||||
"B8:27:EB:5A:1C:1E": "Wilkinson 39 WS 1-2",
|
||||
"B8:27:EB:A0:E9:F9": "Free 40 WS 1-2",
|
||||
"B8:27:EB:DA:8D:EA": "Wilkinson 39 WS 1-1",
|
||||
"B8:27:EB:9A:2E:F0": "Free 32 WS 3-10C",
|
||||
"B8:27:EB:06:D1:C0": "Free 40 WS 5-6",
|
||||
"B8:27:EB:75:D2:6A": "Free 40 WS 1-4",
|
||||
"B8:27:EB:E0:0B:2C": "Free 40 WS 1-6",
|
||||
"B8:27:EB:01:75:8E": "Free 32 WS 3-10A",
|
||||
"B8:27:EB:06:2E:17": "Wilkinson 34 WS 9-10",
|
||||
"B8:27:EB:6D:7F:6C": "Wilkinson 33 WS 10-3A",
|
||||
"B8:27:EB:7D:E9:F8": "Wilkinson 33 WS 10-3B",
|
||||
"B8:27:EB:1C:C4:49": "Wilkinson 33 WS 10-1B",
|
||||
"B8:27:EB:F9:71:92": "Wilkinson 33 WS 6-7",
|
||||
"B8:27:EB:D4:CB:E4": "Free 32 WS 3-10B",
|
||||
"B8:27:EB:0E:6A:13": "LimeQuest 5 WS 9-9",
|
||||
"B8:27:EB:2B:D6:59": "LimeQuest 5 WS 6-8",
|
||||
"B8:27:EB:92:A0:18": "LimeQuest 5 WS 2-4",
|
||||
"B8:27:EB:92:65:DF": "LimeQuest 5 WS 8-5",
|
||||
"B8:27:EB:5C:4E:E4": "LimeQuest 5 WS 7-5",
|
||||
"B8:27:EB:0E:2E:F2": "LimeQuest 5 WS 4-7",
|
||||
"B8:27:EB:C4:7E:50": "Horton 23 WS 5-6",
|
||||
"B8:27:EB:1E:A1:F7": "Horton 23 WS 8-6",
|
||||
"B8:27:EB:FA:2D:73": "Horton 23 WS 6-6",
|
||||
"B8:27:EB:BD:3B:55": "Horton 34 WS 1-2",
|
||||
"B8:27:EB:A7:7F:6F": "Horton 23 WS 5-2",
|
||||
"B8:27:EB:2F:C5:8C": "Horton 23 WS 5-5",
|
||||
"B8:27:EB:E9:C5:7D": "Wilkinson 37 WS 1-9B",
|
||||
"B8:27:EB:96:A0:2D": "Wilkinson 39 WS 2-2",
|
||||
"C4:93:00:0D:BB:42": "Wilkinson 37 WS 1-8",
|
||||
"B8:27:EB:B8:9B:A7": "Wilkinson 1 WS 9-4B",
|
||||
"C4:93:00:0D:BB:45": "ToolBox South",
|
||||
"C4:93:00:08:CF:C0": "Carmanita WW 12-2",
|
||||
"C4:93:00:08:CF:BA": "Carmanita WW 12-1",
|
||||
"C4:93:00:08:CF:0C": "Banay North Frac Pit",
|
||||
"C4:93:00:08:D4:31": "Banay South Frac Pit",
|
||||
"C4:93:00:0A:8A:0D": "Banay South Inlet",
|
||||
"C4:93:00:09:4C:EE": "Banay WW 18 #3",
|
||||
"C4:93:00:0B:0C:D5": "Carmanita WW 12-3",
|
||||
"C4:93:00:0C:AA:FF": "Banay WW 8-5",
|
||||
"C4:93:00:0D:F1:5D": "Banay WW 8-2",
|
||||
"C4:93:00:0D:E8:9F": "Banay WW 6-1",
|
||||
"C4:93:00:0D:F1:87": "Banay WW 18 #10",
|
||||
"C4:93:00:03:7C:DC": "Carmanita WW 12-4",
|
||||
"C4:93:00:0D:F5:56": "Banay WW 18 #1",
|
||||
"00:00:00:00:00:04": "Caden WW #1",
|
||||
"00:00:00:00:00:05": "Caden WW #2",
|
||||
"00:00:00:00:00:06": "Caden WW #3",
|
||||
"00:00:00:00:00:07": "Caden WW #4",
|
||||
"00:00:00:00:00:09": "Lisa WW #1",
|
||||
"00:00:00:00:00:08": "Caden WW #6",
|
||||
"00:00:00:00:00:16": "Laurie Gwen WW #1",
|
||||
"00:00:00:00:00:10": "Jessica WW #4",
|
||||
"00:00:00:00:00:12": "Jessica WW #1",
|
||||
"00:00:00:00:00:13": "Jessica WW #2",
|
||||
"B8:27:EB:A9:DF:E5": "Denali East Frac Pit",
|
||||
"C4:93:00:0D:F1:C0": "Banay WW 8-4",
|
||||
"00:00:00:00:00:17": "Jessica WW #5",
|
||||
"C4:93:00:0B:0C:F6": "Map Rock Transfer Pump Monitor",
|
||||
"B8:27:EB:AA:8A:53": "LimeQuest 5 WS 7-9",
|
||||
"C4:93:00:09:51:BF": "Banay North Pit Inlet #1",
|
||||
"C4:93:00:0D:F2:B9": "Banay North Pit Outlet #1",
|
||||
"C4:93:00:0D:F5:44": "Yvonne Frac Pit",
|
||||
"B8:27:EB:BE:09:91": "Denali Frac Pit",
|
||||
"B8:27:EB:DF:53:70": "Horton 34 WS 1-4",
|
||||
"00:00:02:00:00:02": "Cindy #1",
|
||||
"00:00:02:00:00:08": "Cindy #3",
|
||||
"00:00:02:00:00:11": "Cindy #2",
|
||||
"00:00:03:00:00:03": "Lindsey #3",
|
||||
"00:00:02:00:00:09": "Elizabeth 1",
|
||||
"00:00:02:00:00:13": "Railway 12-3",
|
||||
"00:00:02:00:00:14": "Railway 12-2",
|
||||
"00:00:02:00:00:15": "Elizabeth B1",
|
||||
"00:00:02:00:00:16": "Elizabeth B2",
|
||||
"00:00:02:00:00:17": "Rhonda 1",
|
||||
"00:00:02:00:00:18": "Sec 46 #1",
|
||||
"00:00:02:00:00:19": "Cynthia 1",
|
||||
"00:00:02:00:00:20": "Nancy #2",
|
||||
"00:00:02:00:00:21": "Nancy #1",
|
||||
"00:00:02:00:00:22": "Rhonda Pit",
|
||||
"00:00:03:00:00:05": "Jitterbug 28-1",
|
||||
"00:00:03:00:00:06": "Reagan #1",
|
||||
"00:00:00:00:00:19": "Aurora 7",
|
||||
"00:00:00:00:00:20": "Aurora 8",
|
||||
"00:00:00:00:00:21": "Aurora 9",
|
||||
"00:00:00:00:00:22": "Aurora 10",
|
||||
"00:00:00:00:00:23": "Aurora 11",
|
||||
"00:00:00:00:00:24": "Aurora 6",
|
||||
"00:00:05:00:00:01": "RebJean #2",
|
||||
"00:00:05:00:00:02": "Terri #6",
|
||||
"00:00:05:00:00:03": "RobJane #2",
|
||||
"00:00:05:00:00:04": "RobJane #3",
|
||||
"00:00:05:00:00:05": "RebJean #1",
|
||||
"00:00:05:00:00:06": "RobJane #1",
|
||||
"00:00:05:00:00:07": "Kelsey #2",
|
||||
"00:00:05:00:00:09": "Stephanie 41 #2",
|
||||
"00:00:05:00:00:10": "Kelsey #1",
|
||||
"00:00:05:00:00:11": "Stephanie 41 #3",
|
||||
"00:00:05:00:00:12": "RobJane #4",
|
||||
"00:00:05:00:00:16": "Terri #2",
|
||||
"00:00:05:00:00:15": "Terri #1",
|
||||
"00:00:05:00:00:14": "Terri #3",
|
||||
"00:00:05:00:00:13": "Terri #4",
|
||||
"B8:27:EB:80:2E:F7": "LimeQuest 5 WS 3-5",
|
||||
"00:00:05:00:00:18": "Mary 43 #3",
|
||||
"00:00:05:00:00:19": "Mary 43 #5",
|
||||
"00:00:05:00:00:20": "Mary 43 #2",
|
||||
"00:00:05:00:00:21": "Mary 43 #1",
|
||||
"00:00:05:00:00:22": "KD #2",
|
||||
"00:00:05:00:00:23": "KD #4",
|
||||
"00:00:05:00:00:24": "KD #7",
|
||||
"00:00:05:00:00:25": "KD #5",
|
||||
"00:00:02:00:00:01": "Bobbie #1",
|
||||
"00:00:02:00:00:03": "Bobbie #2",
|
||||
"00:00:02:00:00:04": "Elizabeth A1",
|
||||
"00:00:02:00:00:05": "Patty #1",
|
||||
"C4:93:00:0D:F2:80": "Free Transfer Pit",
|
||||
"00:00:02:00:00:06": "Rhonda 2",
|
||||
"B8:27:EB:10:F5:1C": "Wilkinson 34 WS 5-10",
|
||||
"B8:27:EB:C6:4D:A1": "Wilkinson 33 WS 5-2",
|
||||
"B8:27:EB:FC:49:51": "Wilkinson 33 WS 6-3",
|
||||
"B8:27:EB:1C:72:30": "Wilkinson 37 WS 7-8",
|
||||
"B8:27:EB:CE:5D:4C": "Wilkinson 33 WS 4-1",
|
||||
"B8:27:EB:B8:E9:52": "Wilkinson 37 WS 8-8",
|
||||
"B8:27:EB:D8:B8:B6": "Wilkinson 34 WS 1-8",
|
||||
"B8:27:EB:4F:F2:44": "Wilkinson 39 WS 2-4",
|
||||
"00:00:00:00:00:25": "Trumann 1",
|
||||
"00:00:00:00:00:26": "Trumann 3",
|
||||
"00:00:00:00:00:27": "Trumann 4",
|
||||
"00:00:00:00:00:28": "Trumann 5",
|
||||
"00:00:00:00:00:29": "Trumann 2",
|
||||
"00:00:02:00:00:07": "Patty #2",
|
||||
"B8:27:EB:A6:A8:9A": "Wilkinson 37 WS 10-9",
|
||||
"B8:27:EB:E4:44:DA": "Wilkinson 33 WS 3-1",
|
||||
"B8:27:EB:E0:0B:44": "Wilkinson 34 WS 2-10",
|
||||
"B8:27:EB:8C:68:2A": "Wilkinson 37 WS 1-5",
|
||||
"B8:27:EB:9B:FE:97": "Wilkinson 37 WS 3-5",
|
||||
"B8:27:EB:0E:B3:E2": "Wilkinson 37 WS 3-6",
|
||||
"B8:27:EB:D6:93:8B": "Wilkinson 37 WS 5-7",
|
||||
"00:00:01:00:00:14": "Kate A1",
|
||||
"00:00:01:00:00:15": "Kate A2",
|
||||
"00:00:01:00:00:16": "Kate B1",
|
||||
"00:00:01:00:00:17": "Tessa Lyn",
|
||||
"00:00:02:00:00:10": "Patty #3",
|
||||
"00:00:05:00:00:26": "Smith #1",
|
||||
"00:00:05:00:00:27": "Smith #2",
|
||||
"00:00:05:00:00:28": "Dorcus",
|
||||
"00:00:06:00:00:01": "Monique #1",
|
||||
"00:00:06:00:00:02": "Monique #2",
|
||||
"00:00:06:00:00:03": "Monique #3",
|
||||
"00:00:06:00:00:04": "Dawn #2",
|
||||
"00:00:06:00:00:05": "Dawn #3",
|
||||
"00:00:02:00:00:24": "Yvonne Transfer Pump 3",
|
||||
"00:00:02:00:00:25": "Yvonne Transfer Pump 2",
|
||||
"00:00:02:00:00:26": "Yvonne Transfer Pump 1",
|
||||
"00:00:02:00:00:27": "Bobbie #3",
|
||||
"00:00:05:00:00:29": "Kelsey Pit",
|
||||
"B8:27:EB:83:24:8C": "Wilkinson 34 WS 10-9",
|
||||
"C4:93:00:0D:F0:01": "Banay WW 18 #5",
|
||||
"B8:27:EB:E5:59:03": "Wilkinson 39 WS 1-10",
|
||||
"B8:27:EB:C8:1C:07": "Wilkinson 37 WS 4-7",
|
||||
"C4:93:00:0D:EF:FB": "Banay WW 5-2",
|
||||
"C4:93:00:0D:E8:69": "Banay WW 8-3",
|
||||
"C4:93:00:0D:EF:53": "Banay WW 18 #7",
|
||||
"C4:93:00:0D:F0:0D": "Banay WW 806 North",
|
||||
"C4:93:00:0D:E8:75": "Banay WW 806 South",
|
||||
"00:00:07:00:00:01": "Banay WW 18 #8",
|
||||
"C4:93:00:0D:F3:73": "Denali East Inlet",
|
||||
"B8:27:EB:18:05:D6": "Wilkinson 39 WS 2-8",
|
||||
"C4:93:00:0D:F1:36": "Wilkinson Ranch 39 SR 1-1",
|
||||
"C4:93:00:0D:E0:EF": "Wilkinson 37 WS 1-7",
|
||||
"B8:27:EB:62:ED:99": "LimeQuest 5 WS 8-9",
|
||||
"B8:27:EB:CA:94:0F": "LimeQuest 5 WS 1-4",
|
||||
"B8:27:EB:47:EB:AE": "LimeQuest 10 WS 3-6",
|
||||
"C4:93:00:0B:0C:C9": "Wrage 33 SR 3-3",
|
||||
"C4:93:00:0D:F1:A8": "N. Wilkinson Transfer Lite",
|
||||
"B8:27:EB:C6:E5:B3": "Wilkinson 33 WS 10-4",
|
||||
"B8:27:EB:A9:BE:D4": "Wilkinson 34 WS 9-9",
|
||||
"00:00:03:00:00:01": "Lindsey #1",
|
||||
"00:00:03:00:00:02": "Lindsey #2",
|
||||
"B8:27:EB:95:68:93": "Wilkinson 1 WS 2-10",
|
||||
"B8:27:EB:56:42:2B": "Wilkinson 33 ws 10-1A",
|
||||
"C4:93:00:0D:F2:89": "Denali East Transfer Pump Monitor",
|
||||
"C4:93:00:08:C6:81": "Map Rock Transfer Pump Monitor #2",
|
||||
"B8:27:EB:47:6B:9D": "Wilkinson 37 WS 1-10",
|
||||
"B8:27:EB:51:CC:BC": "Wilkinson 1 WS 1-10A",
|
||||
"B8:27:EB:EB:6A:81": "Horton 34 WS 1-3",
|
||||
"B8:27:EB:19:83:AB": "Wilkinson 39 ws 3-8",
|
||||
"B8:27:EB:5E:49:A6": "Wilkinson 34 WS 6-10",
|
||||
"B8:27:EB:6E:7B:1B": "Free 40 SR 2-1",
|
||||
"C4:93:00:08:D4:13": "Nail Ranch 12 SR 1-3",
|
||||
"B8:27:EB:5D:DD:09": "Wilkinson 33 WS 6-2",
|
||||
"B8:27:EB:FD:A2:43": "Wilkinson 39 WS 1-7",
|
||||
"B8:27:EB:D1:BC:61": "Wilkinson 2 WS 2-9",
|
||||
"C4:93:00:0D:E9:41": "Dawn Frac Pit",
|
||||
"B8:27:EB:8A:A9:65": "Wilkinson 34 WS 10-10",
|
||||
"B8:27:EB:A8:41:F0": "Wilkinson 39 WS 2-10",
|
||||
"B8:27:EB:7C:D7:C5": "Free 40 WS 1-1",
|
||||
"00:00:00:00:00:01": "Barnett 19-2 WW",
|
||||
"00:00:00:00:00:31": "Barnett 24-1",
|
||||
"B8:27:EB:42:C3:4C": "Wilkinson 39 WS 1-6",
|
||||
"C4:93:00:08:CF:18": "ToolBox North",
|
||||
"B8:27:EB:50:EE:26": "Wilkinson 33 WS 10-2",
|
||||
"C4:93:00:0B:0C:DE": "Nail Ranch 37 SR 3-2",
|
||||
"B8:27:EB:28:F9:49": "Wilkinson 37 WS 8-6",
|
||||
"00:00:02:00:00:28": "Nancy Pit",
|
||||
"C4:93:00:0D:E9:53": "Banay WW 18 #2",
|
||||
"C4:93:00:0D:EF:26": "Banay WW 18 #6",
|
||||
"C4:93:00:0D:F1:C6": "Banay WW 6-2",
|
||||
"C4:93:00:0D:E9:3E": "Banay WW #7",
|
||||
"00:18:05:1E:AE:B8": "Banay WW 7-2",
|
||||
"00:18:05:1F:8D:0B": "Penny North",
|
||||
"00:18:05:1F:8D:0E": "Penny South",
|
||||
"B8:27:EB:96:3C:23": "Wilkinson 37 WS 5-5",
|
||||
"C4:93:00:06:71:AA": "LLL 6 SR 1-1",
|
||||
"B8:27:EB:48:AA:63": "Wilkinson 39 WS 1-9",
|
||||
"B8:27:EB:40:0E:B2": "Wilkinson 39 WS 1-8",
|
||||
"B8:27:EB:2D:86:50": "Wilkinson 39 WS 2-6",
|
||||
"B8:27:EB:01:6C:FC": "LimeQuest 5 WS 10-9",
|
||||
"B8:27:EB:28:E1:D6": "Baylee Pit",
|
||||
"00:00:06:00:00:06": "Dawn to Terri",
|
||||
"C4:93:00:0E:E9:EE": "Baylee Pit Transfer",
|
||||
"00:00:05:00:00:31": "TM1",
|
||||
"00:00:05:00:00:30": "TM2",
|
||||
"00:00:05:00:00:32": "WC41-1",
|
||||
"00:00:05:00:00:33": "WC41-2",
|
||||
"00:00:05:00:00:34": "WC41-3",
|
||||
"00:00:00:00:00:33": "Jordan Pit Pump#1",
|
||||
"00:00:00:00:00:34": "Jordan Pit Pump #2",
|
||||
"00:00:00:00:00:35": "Jessica #6",
|
||||
"C4:93:00:0D:F2:41": "Jones A",
|
||||
"00:00:01:00:00:23": "Kelly #1",
|
||||
"00:00:01:00:00:24": "Kelly #2",
|
||||
"00:00:01:00:00:25": "Kelly #3",
|
||||
"02:42:AC:11:00:04": "RPi Test Device",
|
||||
"B8:27:EB:D6:9E:0D": "piflow test"
|
||||
}
|
||||
BIN
meshifyDrivers/.DS_Store
vendored
BIN
meshifyDrivers/.DS_Store
vendored
Binary file not shown.
16
meshifyDrivers/M1/config.txt
Normal file
16
meshifyDrivers/M1/config.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"driverFileName": "m1-7.py",
|
||||
"deviceName": "M1",
|
||||
"driverId": "0030",
|
||||
"releaseVersion": "37",
|
||||
"files": {
|
||||
"file1": "m1-7.py",
|
||||
"file2": "minimalmodbusM1.py",
|
||||
"file3": "minimalmodbus.py",
|
||||
"file4": "device_base.py",
|
||||
"file5": "gsmgps.py",
|
||||
"file6": "mcu_main.py",
|
||||
"file7": "vpn.py",
|
||||
"file8": "logger.py"
|
||||
}
|
||||
}
|
||||
229
meshifyDrivers/M1/device_base.py
Normal file
229
meshifyDrivers/M1/device_base.py
Normal file
@@ -0,0 +1,229 @@
|
||||
import types
|
||||
import traceback
|
||||
import binascii
|
||||
import threading
|
||||
import time
|
||||
import thread
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import textwrap
|
||||
import re
|
||||
|
||||
class deviceBase():
|
||||
|
||||
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
|
||||
self.offset = offset
|
||||
self.company = companyId
|
||||
self.name = name
|
||||
self.number = number
|
||||
self.q = Q
|
||||
self.deviceName = name + '_[' + mac + ':' + number[0:2] + ':' + number[2:] + ']!'
|
||||
self.chName = "M1" + '_[' + mac + ':'
|
||||
self.chName2 = '_[' + mac + ':'
|
||||
print 'device name is:'
|
||||
print self.deviceName
|
||||
mac2 = mac.replace(":", "")
|
||||
self.mac = mac2.upper()
|
||||
self.address = 1
|
||||
self.debug = True
|
||||
self.mcu = mcu
|
||||
self.firstRun = True
|
||||
self.mqtt = mqtt
|
||||
self.nodes = Nodes
|
||||
#local dictionary of derived nodes ex: localNodes[tank_0199] = self
|
||||
self.localNodes = {}
|
||||
os.system("chmod 777 /root/reboot")
|
||||
os.system("echo nameserver 8.8.8.8 > /etc/resolv.conf")
|
||||
|
||||
|
||||
def sendtodbLoc(self, ch, channel, value, timestamp, deviceName, mac):
|
||||
|
||||
|
||||
#this will add your derived nodes the master nodes list, allowing them to receive sets!!
|
||||
localNodesName = deviceName + "_" + str(ch) + "99"
|
||||
|
||||
if not self.localNodes.has_key(localNodesName):
|
||||
self.localNodes[localNodesName] = True
|
||||
self.nodes[localNodesName] = self
|
||||
|
||||
#make the techname
|
||||
lst = textwrap.wrap(str(mac), width=2)
|
||||
tech = ""
|
||||
for i in range(len(lst)):
|
||||
tech += lst[i].lower() + ":"
|
||||
|
||||
|
||||
chName2 = '_[' + tech
|
||||
|
||||
if int(ch) < 10:
|
||||
ch = "0" + str(int(ch))
|
||||
|
||||
if len(ch) > 2:
|
||||
ch = ch[:-2]
|
||||
|
||||
dname = deviceName + chName2 + str(ch) + ":98]!"
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":"%s"}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodbDevJSON(self, ch, channel, value, timestamp, deviceName):
|
||||
|
||||
if int(ch) < 10:
|
||||
ch = "0" + str(int(ch))
|
||||
dname = deviceName + self.chName2 + str(ch) + ":99]!"
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":%s}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodbLora(self, ch, channel, value, timestamp, deviceName):
|
||||
|
||||
if ":" not in ch:
|
||||
ch = ch[0:2] + ":" + ch[2:4]
|
||||
|
||||
#this will add your derived nodes the master nodes list, allowing them to receive sets!!
|
||||
localNodesName = deviceName + "_" + str(ch).replace(':', "")
|
||||
|
||||
if not self.localNodes.has_key(localNodesName):
|
||||
self.localNodes[localNodesName] = True
|
||||
self.nodes[localNodesName] = self
|
||||
|
||||
|
||||
|
||||
dname = deviceName + self.chName2 + str(ch) + "]!"
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":"%s"}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodbDev(self, ch, channel, value, timestamp, deviceName):
|
||||
|
||||
|
||||
#this will add your derived nodes the master nodes list, allowing them to receive sets!!
|
||||
localNodesName = deviceName + "_" + str(ch) + "99"
|
||||
|
||||
if not self.localNodes.has_key(localNodesName):
|
||||
self.localNodes[localNodesName] = True
|
||||
self.nodes[localNodesName] = self
|
||||
|
||||
if int(ch) < 10:
|
||||
ch = "0" + str(int(ch))
|
||||
|
||||
dname = deviceName + self.chName2 + str(ch) + ":99]!"
|
||||
|
||||
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":"%s"}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodbCH(self, ch, channel, value, timestamp):
|
||||
|
||||
|
||||
if int(ch) < 10:
|
||||
ch = "0" + str(ch)
|
||||
|
||||
dname = self.chName + str(ch) + ":99]!"
|
||||
|
||||
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":"%s"}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodb(self, channel, value, timestamp):
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
if timestamp < 1400499858:
|
||||
return
|
||||
else:
|
||||
timestamp = str(int(timestamp) + int(self.offset))
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", self.deviceName)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":"%s"}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
|
||||
def sendtodbJSON(self, channel, value, timestamp):
|
||||
|
||||
if int(timestamp) == 0:
|
||||
timestamp = self.getTime()
|
||||
if timestamp < 1400499858:
|
||||
return
|
||||
else:
|
||||
timestamp = str(int(timestamp) + int(self.offset))
|
||||
|
||||
csplit = re.split(r"(.*?)_\[(.*?)\]", self.deviceName)
|
||||
nodeTypeName = csplit[1]
|
||||
uniqueID = csplit[2]
|
||||
company = "194"
|
||||
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
print topic
|
||||
msg = """[{"value":%s}]""" % (str(value))
|
||||
print msg
|
||||
self.q.put([topic, msg, 0])
|
||||
def getTime(self):
|
||||
return str(int(time.time() + int(self.offset)))
|
||||
|
||||
|
||||
|
||||
|
||||
137
meshifyDrivers/M1/gsmgps.py
Normal file
137
meshifyDrivers/M1/gsmgps.py
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/python
|
||||
import serial
|
||||
import time
|
||||
import re
|
||||
|
||||
class gsmgps:
|
||||
#handles the serial connection from linux to the MCU to the xbee
|
||||
|
||||
def __init__(self):
|
||||
self.ser = serial.Serial(port='/dev/ttyACM0', baudrate=115200, bytesize=8, timeout=0.1)
|
||||
self.ser.open()
|
||||
|
||||
|
||||
def reader(self):
|
||||
|
||||
buf = "ate0\r"
|
||||
self.ser.write(buf)
|
||||
dummy_str = self.ser.read(1000)
|
||||
|
||||
buf = "at+csq\r"
|
||||
self.ser.write(buf)
|
||||
gsm_signal_str = self.ser.read(1000)
|
||||
#print gsm_signal_str
|
||||
gsm_signal_str = gsm_signal_str.split("\r\n")
|
||||
#print gsm_signal_str
|
||||
|
||||
buf = "at$gpsacp\r"
|
||||
self.ser.write(buf)
|
||||
gps_str = self.ser.read(1000)
|
||||
gps_str = gps_str.split("\r\n")
|
||||
|
||||
|
||||
buf = "at+cops?\r"
|
||||
self.ser.write(buf)
|
||||
connection_type_str = self.ser.read(1000)
|
||||
connection_type_str = connection_type_str.split("\r\n")
|
||||
|
||||
|
||||
buf = "at$gpsp=1\r"
|
||||
self.ser.write(buf)
|
||||
|
||||
#self.ser.close()
|
||||
status = []
|
||||
status.append(gsm_signal_str[1])
|
||||
status.append(gps_str[1])
|
||||
status.append(connection_type_str[1])
|
||||
return status
|
||||
|
||||
|
||||
|
||||
def parse_cops(self, _response):
|
||||
try:
|
||||
response = _response.split(',')
|
||||
connType = int(response[3])
|
||||
return connType
|
||||
except Exception, e:
|
||||
print "error in gsmgps parse_cops()"
|
||||
print e
|
||||
print _response
|
||||
return 0
|
||||
|
||||
|
||||
def parse_csq(self, status):
|
||||
|
||||
status = re.findall(r'\d+',status)
|
||||
signal = int(status[0])
|
||||
# actual CSQ signal can be reported between 2 - 30
|
||||
# 99 means no signal in any carrier
|
||||
if (signal < 1) and (signal > 40):
|
||||
return -1
|
||||
signal = 113 - (signal * 2)
|
||||
percent = ((2*(109.00-float(signal)))/113.00) * 100
|
||||
if percent > 100:
|
||||
percent = 100
|
||||
#signal = signal - 2;
|
||||
#signal = signal * 100 / 28
|
||||
return round(percent)
|
||||
|
||||
def parse_gps(self, status):
|
||||
coordinates = []
|
||||
|
||||
status = status.split(",")
|
||||
if status[1] == '' or status[2] == '' or status[5] == '' or status[10] == '':
|
||||
status[1] = "0000.0000N"
|
||||
status[2] = "000.0000W"
|
||||
status[5] = "0"
|
||||
status[10] = "0"
|
||||
|
||||
# latitude
|
||||
degrees = int(status[1][:2])
|
||||
minutes = float(status[1][2:-1])
|
||||
degrees = degrees + (minutes / 60)
|
||||
if status[1][-1:] == "S":
|
||||
degrees = - degrees
|
||||
coordinates.append(degrees)
|
||||
|
||||
#longitude
|
||||
degrees = int(status[2][:3])
|
||||
minutes = float(status[2][3:-1])
|
||||
degrees = degrees + (minutes / 60)
|
||||
if status[2][-1:] == "W":
|
||||
degrees = - degrees
|
||||
coordinates.append(degrees)
|
||||
|
||||
|
||||
# fix status
|
||||
# valid fix 2 or 3
|
||||
if (int(status[5]) < 2):
|
||||
status[5] = 0
|
||||
else:
|
||||
status[5] = 1
|
||||
|
||||
coordinates.append(int(status[5]))
|
||||
# sattelite count
|
||||
coordinates.append(int(status[10]))
|
||||
|
||||
return coordinates
|
||||
|
||||
def main(self):
|
||||
|
||||
return_list = []
|
||||
|
||||
status = self.reader()
|
||||
#print status
|
||||
|
||||
gsm_signal = self.parse_csq(status[0])
|
||||
gps_loc = self.parse_gps(status[1])
|
||||
connection_type = self.parse_cops(status[2])
|
||||
#gps_loc = parse_gps("122330.000,5942.8106N,043.2720W,2.25,338.0,3,0.0,0.02,0.01,240613,04")
|
||||
|
||||
return_list.append(gsm_signal)
|
||||
return_list.append(gps_loc)
|
||||
return_list.append(connection_type)
|
||||
|
||||
#print "GSM signal %d %%" % gsm_signal
|
||||
#print "Latitude: %f , longitude: %f , fix: %d , sattelites: %d" % (gps_loc[0],gps_loc[1],gps_loc[2],gps_loc[3])
|
||||
return return_list
|
||||
67
meshifyDrivers/M1/logger.py
Normal file
67
meshifyDrivers/M1/logger.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import datetime as dt
|
||||
import time
|
||||
|
||||
class Logger(object):
|
||||
''' This logger reports status messages to an M1 channel. It can be turned on and off.
|
||||
|
||||
Attributes:
|
||||
channel_name: the M1 channel name for reporting logs
|
||||
message_sender: function that sends the log message, with the following arguments:
|
||||
(channel, message, qos)
|
||||
enabled: whether or not ot send log messages
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, channel_name, message_sender, enabled=False):
|
||||
self.channel_name = channel_name
|
||||
self.enabled = enabled
|
||||
self.message_sender = message_sender
|
||||
self.last_send = dt.datetime.utcnow()
|
||||
self.buffer = ""
|
||||
print("Logger initialized, reporting to channel " + self.channel_name)
|
||||
|
||||
def log_message(self, message):
|
||||
|
||||
now = dt.datetime.utcnow()
|
||||
# meshify database can only save one message per second per channel, so we buffer text
|
||||
|
||||
if self.enabled:
|
||||
self.buffer += str(message)
|
||||
if (now - self.last_send).total_seconds() > 1:
|
||||
print("Sending log to %s: %s" % (self.channel_name, message))#this should probably print buffer not message
|
||||
try:
|
||||
self.buffer = self.jsonify(self.buffer)
|
||||
self.message_sender(self.channel_name, self.buffer, 0)
|
||||
self.last_send = now
|
||||
self.buffer = ""
|
||||
except Exception as e:
|
||||
print("Logger error: " + e)
|
||||
else:
|
||||
print("Buffered messages on %s" % self.channel_name)
|
||||
self.buffer += " ... "
|
||||
|
||||
def enable(self):
|
||||
self.enabled = True
|
||||
print("Logger %s enabled" % self.channel_name)
|
||||
self.log_message("Logging enabled")
|
||||
|
||||
def disable(self):
|
||||
if self.buffer:
|
||||
time.sleep(1)
|
||||
self.log_message("Logging disabled")
|
||||
print("Logger %s disabled" % self.channel_name)
|
||||
self.enabled = False
|
||||
|
||||
|
||||
def is_enabled(self):
|
||||
return self.enabled
|
||||
|
||||
def jsonify(self, data):
|
||||
data = data.replace("\\","\\\\")#lol
|
||||
data = data.replace("\n", "\\\n")
|
||||
data = data.replace("\r", "\\\r")
|
||||
data = data.replace("\b", "\\\b")
|
||||
data = data.replace("\f", "\\\f")
|
||||
data = data.replace("\t", "\\\t")
|
||||
data = data.replace("\"", "\\\"")
|
||||
return data
|
||||
3217
meshifyDrivers/M1/m1-7.py
Normal file
3217
meshifyDrivers/M1/m1-7.py
Normal file
File diff suppressed because it is too large
Load Diff
860
meshifyDrivers/M1/mcu_main.py
Normal file
860
meshifyDrivers/M1/mcu_main.py
Normal file
@@ -0,0 +1,860 @@
|
||||
import types
|
||||
import traceback
|
||||
import binascii
|
||||
import threading
|
||||
import time
|
||||
import thread
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import serial
|
||||
import update_mcu
|
||||
import gsmgps
|
||||
from xml.dom.minidom import parseString
|
||||
from math import radians, cos, sin, asin, sqrt
|
||||
import Queue
|
||||
import pickle
|
||||
import base64
|
||||
|
||||
|
||||
map1 = {
|
||||
"opc_pm1":"pm1",
|
||||
"opc_pm2_5":"pm2_5",
|
||||
"opc_pm10":"pm10",
|
||||
"pm1":"pm1",
|
||||
"pm2_5":"pm2_5",
|
||||
"pm10":"pm10",
|
||||
"sample_period":"period",
|
||||
"flowrate":"flow",
|
||||
"BIN0":"BIN0",
|
||||
"BIN1":"BIN1",
|
||||
"BIN2":"BIN2",
|
||||
"BIN3":"BIN3",
|
||||
"BIN4":"BIN4",
|
||||
"BIN5":"BIN5",
|
||||
"BIN6":"BIN6",
|
||||
"BIN7":"BIN7",
|
||||
"BIN8":"BIN8",
|
||||
"BIN9":"BIN9",
|
||||
"BIN10":"BIN10",
|
||||
"BIN11":"BIN11",
|
||||
"BIN12":"BIN12",
|
||||
"BIN13":"BIN13",
|
||||
"BIN14":"BIN14",
|
||||
"BIN15":"BIN15",
|
||||
"CL":"cloop",
|
||||
"CL2":"cloop2", # added in LTE Version of M1, there will be either a CL2 or A4, not both
|
||||
"I1":"din1", # both are included here so that dataDict will be populated with the right one
|
||||
"I2":"din2", # based on what the microcontroller sends
|
||||
"I3":"din3",
|
||||
"I4":"din4",
|
||||
"A1":"analog1",
|
||||
"A2":"analog2",
|
||||
"A3":"analog3",
|
||||
"A4":"analog4",
|
||||
"OC1": "dout1",
|
||||
"OC2": "dout2",
|
||||
"OC3": "dout3",
|
||||
"OC4": "dout4",
|
||||
"R1":"relay1",
|
||||
"VIN":"vin",
|
||||
"BAT":"bat",
|
||||
"TMP":"temp",
|
||||
"PULSE":"pulse",
|
||||
"VER" : "ver"
|
||||
}
|
||||
|
||||
IOelements = {
|
||||
"I1":"din1",
|
||||
"I2":"din2",
|
||||
"I3":"din3",
|
||||
"I4":"din4",
|
||||
"OC1": "dout1",
|
||||
"OC2": "dout2",
|
||||
"OC3": "dout3",
|
||||
"OC4": "dout4",
|
||||
"R1":"relay1"
|
||||
}
|
||||
|
||||
|
||||
IOdata = {
|
||||
"1":"On",
|
||||
1: "On",
|
||||
"on": "On",
|
||||
"On": "On",
|
||||
"0": "Off",
|
||||
0: "Off",
|
||||
"off": "Off",
|
||||
"Off": "Off"
|
||||
}
|
||||
|
||||
#fake mqtt message for ifttt actions
|
||||
class mqttMsg(object):
|
||||
|
||||
def __init__(self, topic, payload):
|
||||
self.topic = topic
|
||||
self.payload = payload
|
||||
self.qos = 1
|
||||
|
||||
class xbeeSerial:
|
||||
#handles the serial connection from linux to the MCU to the xbee
|
||||
|
||||
def __init__(self):
|
||||
self.runXbee = False
|
||||
self.data = ""
|
||||
self.lock = threading.Lock()
|
||||
thread.start_new_thread(self.readThread, ())
|
||||
self.writeLock = threading.Lock()
|
||||
self.first_run = True
|
||||
|
||||
#flag to direct data during file transfer
|
||||
self.fileTransfer = False
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def isOpen(self):
|
||||
return True
|
||||
|
||||
def writeAT(self, buf):
|
||||
print "writing XBEE AT: ", buf
|
||||
f_out = os.open('/dev/ttyXBEE_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
|
||||
def write(self, buf):
|
||||
print "writing XBEE: ", buf
|
||||
with self.writeLock:
|
||||
f_out = os.open('/dev/ttyXBEE_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
|
||||
def read(self, max=1000):
|
||||
with self.lock:
|
||||
data = self.data
|
||||
self.data = ""
|
||||
return data
|
||||
def flushInput(self):
|
||||
self.data = ""
|
||||
def flushOutput(self):
|
||||
self.data = ""
|
||||
|
||||
def atCommandGet(self, command):
|
||||
with self.writeLock:
|
||||
#clear out the read buffer:
|
||||
self.read()
|
||||
self.writeAT("+++")
|
||||
time.sleep(2)
|
||||
at = "AT" + command + chr(13)
|
||||
self.writeAT(at)
|
||||
time.sleep(2)
|
||||
return self.read()
|
||||
|
||||
def makeDragon(self):
|
||||
self.atCommandSet("DD", "B0776")
|
||||
time.sleep(4)
|
||||
self.atCommandSet("DD", "B0776")
|
||||
time.sleep(2)
|
||||
os.system("reboot -f")
|
||||
|
||||
def makeFly(self):
|
||||
self.atCommandSet("DD", "B0777")
|
||||
time.sleep(4)
|
||||
self.atCommandSet("DD", "B0777")
|
||||
time.sleep(2)
|
||||
os.system("reboot -f")
|
||||
def atCommandSet(self, command, value):
|
||||
with self.writeLock:
|
||||
#clear out the read buffer:
|
||||
self.read()
|
||||
self.writeAT("+++")
|
||||
time.sleep(2)
|
||||
at = "AT" + command + "=" + value + chr(13)
|
||||
self.writeAT(at)
|
||||
time.sleep(2)
|
||||
self.writeAT("ATWR" + chr(13))
|
||||
|
||||
def readThread(self):
|
||||
|
||||
while self.runXbee:
|
||||
time.sleep(.05)
|
||||
|
||||
try:
|
||||
|
||||
f_in = os.open('/dev/ttyXBEE_TX', os.O_RDONLY)
|
||||
line = os.read(f_in, 10000)
|
||||
print "reading XBEE: ", line
|
||||
os.close(f_in)
|
||||
if self.fileTransfer == False:
|
||||
try:
|
||||
d = base64.b64decode(line)
|
||||
line = d
|
||||
except:
|
||||
pass
|
||||
with self.lock:
|
||||
self.data += line
|
||||
|
||||
|
||||
#this clears the buffer on the first time you open the connection
|
||||
#if self.first_run == True:
|
||||
# self.data = ""
|
||||
# self.first_run = False
|
||||
except Exception,e:
|
||||
try:
|
||||
self.lock.release()
|
||||
except:
|
||||
pass
|
||||
print(str(e))
|
||||
return ""
|
||||
|
||||
|
||||
class rs232Serial:
|
||||
#handles the serial connection from linux to the MCU to the xbee
|
||||
|
||||
def __init__(self):
|
||||
self.data = ""
|
||||
self.lock = threading.Lock()
|
||||
thread.start_new_thread(self.readThread, ())
|
||||
self.first_run = True
|
||||
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def isOpen(self):
|
||||
return True
|
||||
|
||||
def write(self, buf):
|
||||
print "writing 232: ", buf
|
||||
f_out = os.open('/dev/ttyRS232_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
|
||||
def read(self, max=1000):
|
||||
with self.lock:
|
||||
data = self.data
|
||||
self.data = ""
|
||||
return data
|
||||
def flushInput(self):
|
||||
self.data = ""
|
||||
def flushOutput(self):
|
||||
self.data = ""
|
||||
def readThread(self):
|
||||
|
||||
while True:
|
||||
|
||||
try:
|
||||
|
||||
f_in = os.open('/dev/ttyRS232_TX', os.O_RDONLY)
|
||||
line = os.read(f_in, 10000)
|
||||
print "reading 232: ", line
|
||||
os.close(f_in)
|
||||
with self.lock:
|
||||
self.data += line
|
||||
|
||||
|
||||
#this clears the buffer on the first time you open the connection
|
||||
#if self.first_run == True:
|
||||
# self.data = ""
|
||||
# self.first_run = False
|
||||
except Exception,e:
|
||||
try:
|
||||
self.lock.release()
|
||||
except:
|
||||
pass
|
||||
print(str(e))
|
||||
return ""
|
||||
|
||||
|
||||
class rs485Serial:
|
||||
#handles the serial connection from linux to the MCU to the xbee
|
||||
|
||||
def __init__(self):
|
||||
self.data = ""
|
||||
self.lock = threading.Lock()
|
||||
thread.start_new_thread(self.readThread, ())
|
||||
self.first_run = True
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def isOpen(self):
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
def write(self, buf):
|
||||
print "writing 485: ", buf
|
||||
f_out = os.open('/dev/ttyRS485_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
|
||||
def read(self, max=1000, pause=0.1):
|
||||
time.sleep(pause)
|
||||
with self.lock:
|
||||
data = self.data
|
||||
self.data = ""
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def readThread(self):
|
||||
|
||||
while True:
|
||||
|
||||
try:
|
||||
|
||||
f_in = os.open('/dev/ttyRS485_TX', os.O_RDONLY)
|
||||
line = os.read(f_in, 10000)
|
||||
print "reading 485: ", line
|
||||
os.close(f_in)
|
||||
with self.lock:
|
||||
self.data += line
|
||||
|
||||
|
||||
#this clears the buffer on the first time you open the connection
|
||||
#if self.first_run == True:
|
||||
# self.data = ""
|
||||
# self.first_run = False
|
||||
except Exception,e:
|
||||
try:
|
||||
self.lock.release()
|
||||
except:
|
||||
pass
|
||||
print(str(e))
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
class mcu_main(threading.Thread):
|
||||
"""
|
||||
In this class I need to:
|
||||
|
||||
1. make a serial connection to the MCU
|
||||
2. set up a method for sending data to the com port self.write(data)
|
||||
3. set up a thread for checking for data coming in from the com port
|
||||
assumptions here are that the mcu will buffer the incoming messages.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
#global for if the flies on the network will be at this location or their own.
|
||||
self.flySameLocation = True
|
||||
self.xbees = {}
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.last_OK = False
|
||||
self.lock = threading.Lock()
|
||||
self.connected = False
|
||||
self.last_485 = None
|
||||
self.finished = threading.Event()
|
||||
threading.Thread.start(self)
|
||||
self.dataDict = {}
|
||||
self.rs485 = rs485Serial()
|
||||
self.rs232 = rs232Serial()
|
||||
self.xbee = xbeeSerial()
|
||||
self.count = 0
|
||||
self.ledStat = None
|
||||
self.signal = None
|
||||
self.connType = None
|
||||
self.gps = "0.0,-0.0"
|
||||
try:
|
||||
self.gsmgps = gsmgps.gsmgps()
|
||||
except:
|
||||
pass
|
||||
|
||||
self.iftQ = Queue.Queue()
|
||||
self.iftLock = threading.Lock()
|
||||
try:
|
||||
with open('/root/python_firmware/mcu/iftttMap.p', 'rb') as handle:
|
||||
self.iftttMap = pickle.load(handle)
|
||||
print "found pickled iftttMap dictionary"
|
||||
print self.iftttMap
|
||||
except:
|
||||
print "couldn't load iftttMap from pickle"
|
||||
self.iftttMap = {"M1_[c4:93:00:06:71:38:00:30]!":[{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"On"}},
|
||||
{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"Off"}},
|
||||
{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"Off"}},
|
||||
|
||||
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"Off"}},
|
||||
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"On"}},
|
||||
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"Off"}},
|
||||
|
||||
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"Off"}},
|
||||
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"Off"}},
|
||||
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"On"}},
|
||||
|
||||
]}
|
||||
|
||||
with open('/root/python_firmware/mcu/iftttMap.p', 'wb') as handle:
|
||||
pickle.dump(self.iftttMap, handle)
|
||||
|
||||
thread.start_new_thread(self.iftttThread, ())
|
||||
|
||||
|
||||
def set485Baud(self, baud):
|
||||
baud = str(baud)
|
||||
cmd = """<SET COM="RS485BAUD">%s</SET>\n""" % baud
|
||||
success = self.send_mcu(cmd ,retry=5)
|
||||
#self.spiOn(0)
|
||||
return success
|
||||
|
||||
def set232Baud(self, baud):
|
||||
baud = str(baud)
|
||||
cmd = """<SET COM="RS232BAUD">%s</SET>\n""" % baud
|
||||
success = self.send_mcu(cmd ,retry=5)
|
||||
#self.spiOn(0)
|
||||
return success
|
||||
|
||||
def resetModem(self):
|
||||
success = self.send_mcu("""<SET COM="GSMRST">1</SET>\n""" ,retry=5)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def firmUpdate(self, filename):
|
||||
|
||||
with self.lock:
|
||||
self.connected = False
|
||||
self.ser.close()
|
||||
success = update_mcu.update_mcu(filename)
|
||||
print success
|
||||
if success == True:
|
||||
print "we got it working"
|
||||
|
||||
|
||||
return success
|
||||
|
||||
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.finished.set()
|
||||
self.join()
|
||||
|
||||
def getDict(self):
|
||||
data = self.dataDict
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def digitalOut1(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
success = self.send_mcu("""<SET COM="OC1">""" + state + """</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
def digitalOut2(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
success = self.send_mcu("""<SET COM="OC2">""" + state + """</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
def digitalOut3(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
success = self.send_mcu("""<SET COM="OC3">""" + state + """</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
def digitalOut4(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
success = self.send_mcu("""<SET COM="OC4">""" + state + """</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
def digitalOut5(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
success = self.send_mcu("""<SET COM="OC5">""" + state + """</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
|
||||
def relay2(self, state):
|
||||
#state = self.ioValueTest(state)
|
||||
#state = str(state)
|
||||
#success = self.send_mcu("""<SET COM="R2">""" + state + """</SET>\n""" ,retry=5)
|
||||
return True
|
||||
|
||||
|
||||
def relay1(self, state):
|
||||
state = self.ioValueTest(state)
|
||||
state = str(state)
|
||||
if state == "0":
|
||||
buf = """{\"SET\": [{\"R1\": \"0\"}]}\n"""
|
||||
elif state == "1":
|
||||
buf = """{\"SET\": [{\"R1\": \"1\"}]}\n"""
|
||||
success = self.send_mcu(buf ,retry=5)
|
||||
return success
|
||||
|
||||
def ledControl(self, ledNumber, onoff, blinking):
|
||||
|
||||
#str1 = """<SET COM="LED%s">%s</SET>\n""" % (str(ledNumber), str(onoff)) //THESE CAUSE ORANGE AND GREEN BLINKINIG LIGHT ERRORS
|
||||
#str2 = """<SET COM="LEDBL%s">%s</SET>\n""" % (str(ledNumber), str(blinking)) // USE JSON VERSIONS FOR NOW, maybe fix mcu code later
|
||||
|
||||
str1 = """{\"SET\": [{\"LED%s\": \"%s\"}]}\n""" % (str(ledNumber), str(onoff))
|
||||
str2 = """ {\"SET\": [{\"LEDBL%s\": \"%s\"}]}\n""" % (str(ledNumber), str(blinking))
|
||||
success = self.send_mcu(str2, retry=5)
|
||||
time.sleep(.5)
|
||||
success = self.send_mcu(str1, retry=5)
|
||||
|
||||
if success:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def spiOn(self, state):
|
||||
if state == 1 or state == "1" or state == "on" or state == "on":
|
||||
success = self.send_mcu("""<SET COM="OPC">1</SET>\n""" ,retry=5)
|
||||
#self.send_mcu("""<SET COM=\"OPC_FAN_LASER_ON\"></SET>\n""")
|
||||
#self.send_mcu("""{\"SET\": [{\"OPC\": \"1\"}, {\"R1\": \"0\"}, {\"R1\": \"1\"}]}\n""")
|
||||
if state == 0 or state == "0" or state == "off" or state == "Off":
|
||||
self.send_mcu("""<SET COM=\"OPC_FAN_LASER_OFF\"></SET>\n""")
|
||||
self.send_mcu("""{\"SET\": [{\"OPC\": \"0\"}]}\n""")
|
||||
|
||||
|
||||
def xbeeCom(self, state):
|
||||
if state == 1 or state == "1" or state == "on" or state == "on":
|
||||
success = self.send_mcu("""<SET COM="XBEECOM">1</SET>\n""" ,retry=5)
|
||||
if state == 0 or state == "0" or state == "off" or state == "Off":
|
||||
success = self.send_mcu("""<SET COM="XBEECOM">0</SET>\n""" ,retry=5)
|
||||
|
||||
def resetXbee(self):
|
||||
success = self.send_mcu("""<SET COM="XBEERST">1</SET>\n""" ,retry=5)
|
||||
return success
|
||||
|
||||
def rs232reset(self):
|
||||
success = self.send_mcu("""<SET COM="RS232RESET">1</SET>\n""")
|
||||
return success
|
||||
def sleep(self, time):
|
||||
time = str(time)
|
||||
success = self.send_mcu("""<SET COM="SLEEP">""" + time + """</SET>\n""")
|
||||
return success
|
||||
|
||||
def COM_thread(self):
|
||||
|
||||
while True:
|
||||
time.sleep(1.5)
|
||||
try:
|
||||
self.send_mcu_no_response("<GET>STATE</GET>\n")
|
||||
except:
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
|
||||
#thread.start_new_thread(self.RS485_thread, ())
|
||||
thread.start_new_thread(self.COM_thread, ())
|
||||
thread.start_new_thread(self.updateGPSandSignalThread, ())
|
||||
thread.start_new_thread(self.mcuWatchdogThread, ())
|
||||
|
||||
|
||||
while True:
|
||||
time.sleep(.5)
|
||||
try:
|
||||
|
||||
f_in = os.open('/dev/ttyCOM_TX', os.O_RDONLY)
|
||||
|
||||
line = os.read(f_in, 1000)
|
||||
os.close(f_in)
|
||||
|
||||
#print line
|
||||
|
||||
|
||||
|
||||
|
||||
#line = line[0]
|
||||
item = str(line)
|
||||
if "OK" in item or "ok" in item:
|
||||
self.last_OK = True
|
||||
try:
|
||||
x = parseString(item)
|
||||
try:
|
||||
self.count = int(x.getElementsByTagName("STATE")[0].getAttribute("req_cnt"))
|
||||
except:
|
||||
pass
|
||||
#print "here is the count ", self.count
|
||||
for i in x.childNodes:
|
||||
for a in i.childNodes:
|
||||
name = a.localName
|
||||
if name != None:
|
||||
val = x.getElementsByTagName(name)[0].firstChild.nodeValue
|
||||
if name in IOelements:
|
||||
self.dataDict[map1[name]] = self.IOmap(val)
|
||||
else:
|
||||
try:
|
||||
#if name == "A1":
|
||||
# val = float(val) * 0.85
|
||||
#if name == "A2":
|
||||
# val = float(val) * 0.92
|
||||
self.dataDict[map1[name]] = val
|
||||
except:
|
||||
continue
|
||||
except Exception, e:
|
||||
pass#print e
|
||||
|
||||
|
||||
|
||||
except Exception,e:
|
||||
#print(str(e))
|
||||
time.sleep(.5)
|
||||
|
||||
def IOmap(self, value):
|
||||
if IOdata.has_key(value):
|
||||
newVal = IOdata[value]
|
||||
else:
|
||||
newVal = value
|
||||
return newVal
|
||||
|
||||
def ioValueTest(self, value):
|
||||
if value == 0 or value == "0" or value == "off" or value == "Off":
|
||||
newVal = 0
|
||||
elif value == 1 or value == "1" or value == "on" or value == "On":
|
||||
newVal = 1
|
||||
return newVal
|
||||
|
||||
def send_mcu_no_response(self,data):
|
||||
buf = data
|
||||
with self.lock:
|
||||
f_out = os.open('/dev/ttyCOM_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
|
||||
def send_mcu(self, data, retry=0):
|
||||
buf = data
|
||||
|
||||
last_OK = False
|
||||
while retry > -1:
|
||||
retry = (int(retry) -1)
|
||||
|
||||
with self.lock:
|
||||
time.sleep(1)
|
||||
self.last_OK = False
|
||||
f_out = os.open('/dev/ttyCOM_RX', os.O_WRONLY )
|
||||
os.write(f_out, buf)
|
||||
os.close(f_out)
|
||||
count = 0
|
||||
while last_OK == False:
|
||||
|
||||
time.sleep(.5)
|
||||
last_OK = self.last_OK
|
||||
if last_OK == True:
|
||||
retry = -2
|
||||
break
|
||||
count += 1
|
||||
if count > 5:
|
||||
break
|
||||
|
||||
|
||||
return last_OK
|
||||
|
||||
def updateGPSandSignalThread(self):
|
||||
while True:
|
||||
time.sleep(2)
|
||||
try:
|
||||
|
||||
signal, gps, connType = self.getGPSGSM()
|
||||
gps = gps.split(",")
|
||||
|
||||
lat = round(float(gps[0]), 8)
|
||||
long = round(float(gps[1]), 8)
|
||||
gps = str(lat) + "," + str(long)
|
||||
if gps!= self.gps:
|
||||
self.gps = gps
|
||||
|
||||
if connType != self.connType:
|
||||
self.connType = connType
|
||||
#led status 4=solid, 3=blinking fast 2=blinking slow, 1=off
|
||||
if signal != self.signal:
|
||||
self.signal = signal
|
||||
if int(signal) > 46:
|
||||
status = 4
|
||||
elif int(signal) > 28:
|
||||
status = 3
|
||||
elif int(signal) > 1:
|
||||
status = 2
|
||||
else:
|
||||
status = 1
|
||||
if status != self.ledStat:
|
||||
self.ledStat = status
|
||||
if status == 4:
|
||||
self.ledControl(1,1,0)
|
||||
elif status == 3:
|
||||
self.ledControl(1,1,8)
|
||||
elif status == 2:
|
||||
self.ledControl(1,1,120)
|
||||
elif status == 1:
|
||||
self.ledControl(1,0,0)
|
||||
except Exception, e:
|
||||
#print e
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
def distanceBetween(self, lon1, lat1, lon2, lat2):
|
||||
lon1 = float(lon1)
|
||||
lat1 = float(lat1)
|
||||
lon2 = float(lon2)
|
||||
lat2 = float(lat2)
|
||||
"""
|
||||
Calculate the great circle distance between two points
|
||||
on the earth (specified in decimal degrees)
|
||||
"""
|
||||
# convert decimal degrees to radians
|
||||
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
|
||||
|
||||
# haversine formula
|
||||
dlon = lon2 - lon1
|
||||
dlat = lat2 - lat1
|
||||
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
|
||||
c = 2 * asin(sqrt(a))
|
||||
r = 3956 # Radius of earth in kilometers. Use 3956 for miles
|
||||
return c * r
|
||||
def get_modem_id(self):
|
||||
try:
|
||||
mdn = self.gsmgps.get_MDN()
|
||||
except Exception,e:
|
||||
print "error getting modem id"
|
||||
print e
|
||||
return None
|
||||
return mdn
|
||||
|
||||
def get_sim_id(self):
|
||||
try:
|
||||
sim = self.gsmgps.get_SIMID()
|
||||
except Exception,e:
|
||||
print "error getting sim id"
|
||||
print e
|
||||
return None
|
||||
return sim
|
||||
|
||||
def getGPSGSM(self):
|
||||
tries = 0
|
||||
while tries < 10:
|
||||
try:
|
||||
tries += 1
|
||||
a = self.gsmgps.main()
|
||||
signal = a[0]
|
||||
gps = str(a[1][0]) + "," + str(a[1][1])
|
||||
connection_type = a[2]
|
||||
return signal, gps, connection_type
|
||||
except:
|
||||
pass
|
||||
|
||||
return None, None
|
||||
|
||||
def setIftttmap(self, obj):
|
||||
|
||||
with self.iftLock:
|
||||
self.iftttMap = obj
|
||||
with open('/root/python_firmware/mcu/iftttMap.p', 'wb') as handle:
|
||||
pickle.dump(self.iftttMap, handle)
|
||||
|
||||
def iftttThread(self):
|
||||
while True:
|
||||
time.sleep(1)
|
||||
try:
|
||||
data = self.iftQ.get()
|
||||
name = data[0]
|
||||
channel = data[1]
|
||||
value = data[2]
|
||||
with self.iftLock:
|
||||
if name in self.iftttMap:
|
||||
for i in self.iftttMap[name]:
|
||||
trigger = False
|
||||
if i['channel'] == channel:
|
||||
if i["value"].startswith("<"):
|
||||
if "&" in i["value"]:
|
||||
if i["value"].split("&")[1].startswith("<"):
|
||||
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) < float(i["value"].split("&")[1].replace("<", "")):
|
||||
trigger = True
|
||||
elif i["value"].split("&")[1].startswith(">"):
|
||||
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) > float(i["value"].split("&")[1].replace(">", "")):
|
||||
trigger = True
|
||||
elif i["value"].split("&")[1].startswith("="):
|
||||
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) == i["value"].split("&")[1].replace("=", ""):
|
||||
trigger = True
|
||||
else:
|
||||
if float(value) < float(i["value"].replace("<", "")):
|
||||
print "Less than rule triggered"
|
||||
print "we have a pending ifttt action"
|
||||
trigger = True
|
||||
|
||||
|
||||
|
||||
elif i["value"].startswith(">"):
|
||||
if "&" in i["value"]:
|
||||
if i["value"].split("&")[1].startswith("<"):
|
||||
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) < float(i["value"].split("&")[1].replace("<", "")):
|
||||
trigger = True
|
||||
elif i["value"].split("&")[1].startswith(">"):
|
||||
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) > float(i["value"].split("&")[1].replace(">", "")):
|
||||
trigger = True
|
||||
elif i["value"].split("&")[1].startswith("="):
|
||||
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) == i["value"].split("&")[1].replace("=", ""):
|
||||
trigger = True
|
||||
else:
|
||||
if float(value) > float(i["value"].replace(">", "")):
|
||||
print "Greater than rule triggered"
|
||||
print "we have a pending ifttt action"
|
||||
trigger = True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
elif i["value"].startswith("=") or i['value'] == value:
|
||||
if i["value"].replace("=", "") == value:
|
||||
trigger = True
|
||||
|
||||
|
||||
if trigger:
|
||||
print "we have a pending ifttt action"
|
||||
set_value = i['then']['value']
|
||||
set_name = i['then']['name']
|
||||
set_channel = i['then']['channel']
|
||||
topic = "meshify/sets/1/" + self.mac
|
||||
message = '[{"user":"ifttt action","mac":"%s","company":"1","payload":{"name":"%s.%s","value":"%s","expires":"1389369695"},"msgId":0}]' % (self.mac, set_name, set_channel, set_value)
|
||||
self.on_message("n", "j", mqttMsg(topic, message))
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
except Exception,e:
|
||||
print e
|
||||
|
||||
def mcuWatchdogThread(self):
|
||||
time.sleep(3600)
|
||||
while True:
|
||||
old_count = self.count
|
||||
time.sleep(120)
|
||||
if self.count <= old_count:
|
||||
print "reseting, data is not changing"
|
||||
#mcu no longer getting updates.
|
||||
os.system("reboot -f")
|
||||
time.sleep(120)
|
||||
else:
|
||||
pass
|
||||
#print "healthy mcu"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1995
meshifyDrivers/M1/minimalmodbus.py
Normal file
1995
meshifyDrivers/M1/minimalmodbus.py
Normal file
File diff suppressed because it is too large
Load Diff
2028
meshifyDrivers/M1/minimalmodbusM1.py
Normal file
2028
meshifyDrivers/M1/minimalmodbusM1.py
Normal file
File diff suppressed because it is too large
Load Diff
179
meshifyDrivers/M1/vpn.py
Normal file
179
meshifyDrivers/M1/vpn.py
Normal file
@@ -0,0 +1,179 @@
|
||||
import socket
|
||||
import fcntl
|
||||
import struct
|
||||
import os
|
||||
import time
|
||||
import pickle
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
import subprocess
|
||||
#this class will have methods for adding port forwarding, saving the port forward, deleting the port forward, turning the VPN on/off
|
||||
|
||||
"""
|
||||
iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.1.2:80
|
||||
iptables -I FORWARD -p tcp -d 192.168.1.2 --dport 80 -j ACCEPT
|
||||
iptables -t nat -I POSTROUTING -j MASQUERADE
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class vpn():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
try:
|
||||
with open('/root/python_firmware/drivers/portsJSON.p', 'rb') as handle:
|
||||
self.forwardingMap = pickle.load(handle)
|
||||
|
||||
print "found pickled dictionary"
|
||||
print self.forwardingMap
|
||||
except:
|
||||
print "couldn't load devices from pickle"
|
||||
self.forwardingMap = {
|
||||
"1": {
|
||||
"port":"",
|
||||
"externalPort":"",
|
||||
"externalIP":""
|
||||
},
|
||||
"2": {
|
||||
"port":"",
|
||||
"externalPort":"",
|
||||
"externalIP":""
|
||||
},
|
||||
"3": {
|
||||
"port":"",
|
||||
"externalPort":"",
|
||||
"externalIP":""
|
||||
},
|
||||
"4": {
|
||||
"port":"",
|
||||
"externalPort":"",
|
||||
"externalIP":""
|
||||
}
|
||||
}
|
||||
|
||||
def delForward(self, number):
|
||||
|
||||
|
||||
string1 = "iptables -t nat -D PREROUTING -p tcp --dport %s -j DNAT --to %s:%s" % (str(self.forwardingMap[str(number)]["port"]), str(self.forwardingMap[str(number)]["externalIP"]), str(self.forwardingMap[str(number)]["externalPort"]))
|
||||
#string2 = "iptables -I FORWARD -p tcp -d %s --dport %s -j ACCEPT" % (str(ip), str(port))
|
||||
#string3 = "iptables -t nat -I POSTROUTING -j MASQUERADE"
|
||||
os.system(string1)
|
||||
#time.sleep(1)
|
||||
#os.system(string2)
|
||||
#time.sleep(1)
|
||||
#os.system(string3)
|
||||
|
||||
self.forwardingMap[str(number)]["port"] = ""
|
||||
self.forwardingMap[str(number)]["externalPort"] = ""
|
||||
self.forwardingMap[str(number)]["externalIP"] = ""
|
||||
|
||||
with open('/root/python_firmware/drivers/portsJSON.p', 'wb') as handle:
|
||||
pickle.dump(self.forwardingMap, handle)
|
||||
|
||||
print "you are here"
|
||||
|
||||
|
||||
|
||||
|
||||
def addForward(self, number, port, exPort, ip):
|
||||
string1 = "iptables -t nat -I PREROUTING -p tcp --dport %s -j DNAT --to %s:%s" % (str(port), str(ip), str(exPort))
|
||||
string2 = "iptables -I FORWARD -p tcp -d %s --dport %s -j ACCEPT" % (str(ip), str(port))
|
||||
string3 = "iptables -t nat -I POSTROUTING -j MASQUERADE"
|
||||
os.system(string1)
|
||||
time.sleep(1)
|
||||
os.system(string2)
|
||||
time.sleep(1)
|
||||
os.system(string3)
|
||||
|
||||
os.system("iptables -I INPUT -j ACCEPT")
|
||||
os.system("iptables -I FORWARD -j ACCEPT")
|
||||
os.system("iptables -I OUTPUT -j ACCEPT")
|
||||
|
||||
self.forwardingMap[str(number)]["port"] = str(port)
|
||||
self.forwardingMap[str(number)]["externalPort"] = str(exPort)
|
||||
self.forwardingMap[str(number)]["externalIP"] = str(ip)
|
||||
|
||||
with open('/root/python_firmware/drivers/portsJSON.p', 'wb') as handle:
|
||||
pickle.dump(self.forwardingMap, handle)
|
||||
|
||||
def turnOff(self):
|
||||
os.system("killall openvpn")
|
||||
|
||||
def turnOn(self, url, username, password, mac, subnet, ip, domain):
|
||||
os.system("killall openvpn")
|
||||
time.sleep(5)
|
||||
self.get_vpn_config(url, username, password, mac, subnet, ip, domain)
|
||||
time.sleep(10)
|
||||
|
||||
subprocess.call('cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &', shell=True)
|
||||
|
||||
#txt = commands.getstatusoutput("cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &")
|
||||
#os.system("cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &")
|
||||
|
||||
def get_ip_address(self, ifname):
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
return socket.inet_ntoa(fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8915, # SIOCGIFADDR
|
||||
struct.pack('256s', ifname[:15])
|
||||
)[20:24])
|
||||
except:
|
||||
return "VPN Off"
|
||||
|
||||
|
||||
def run_command(self, command):
|
||||
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
return iter(p.stdout.readline, b'')
|
||||
|
||||
def get_vpn_config(self, url, username, password, mac, subnet, ip, domain):
|
||||
if url == "" or url == None:
|
||||
url = "http://54.221.213.207:5000"
|
||||
login_data = {
|
||||
'url':url,
|
||||
'username':username,
|
||||
'password':password,
|
||||
'mac':mac,
|
||||
'subnet':subnet,
|
||||
'ip':ip,
|
||||
'domain':domain
|
||||
}
|
||||
#SERVER = "http://54.196.172.36:5000"
|
||||
rootFilename = os.path.dirname(os.path.realpath(sys.argv[0])) + "/vpn_certs/"
|
||||
print "starting....."
|
||||
with requests.Session() as x:
|
||||
print login_data
|
||||
g = x.post((login_data['url'] + "/config"), data=json.dumps(login_data),
|
||||
headers={"Content-Type": 'application/json'})
|
||||
print g
|
||||
res = json.loads(g.text)
|
||||
|
||||
mac = login_data['mac']
|
||||
f = open((rootFilename + 'ca.crt'),'w')
|
||||
#print res['ca_crt']
|
||||
f.write(res['ca_crt'])
|
||||
f.close()
|
||||
|
||||
filename = (rootFilename + "%s.crt") % (mac)
|
||||
f = open(filename,'w')
|
||||
#print res['client_crt']
|
||||
f.write(res['client_crt'])
|
||||
f.close()
|
||||
|
||||
filename = (rootFilename + "%s.key") % (mac)
|
||||
f = open(filename,'w')
|
||||
#print res['client_key']
|
||||
f.write(res['client_key'])
|
||||
f.close()
|
||||
|
||||
f = open((rootFilename + 'vpn.conf'),'w')
|
||||
f.write(res['conf'])
|
||||
#print res['conf']
|
||||
f.close()
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
{
|
||||
|
||||
"driverFileName":"mainMeshify.py",
|
||||
"deviceName":"mainMeshify",
|
||||
"driverId":"0000",
|
||||
"releaseVersion":"16",
|
||||
"files": {
|
||||
"file1":"mainMeshify.py",
|
||||
"file2":"main.py",
|
||||
"file3":"meshifyData.py"
|
||||
"driverFileName": "mainMeshify.py",
|
||||
"deviceName": "mainMeshify",
|
||||
"driverId": "0000",
|
||||
"releaseVersion": "18",
|
||||
"files": {
|
||||
"file1": "mainMeshify.py",
|
||||
"file2": "main.py",
|
||||
"file3": "device_base.py",
|
||||
"file4": "meshifyData.py"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class main():
|
||||
self.dst = ""
|
||||
# queue for sets to the mesh network will handeled through a queue in this main driver
|
||||
self.meshQ = Queue.Queue()
|
||||
version = "16" # 6 - mistification # 5 - updated for SAT data and generic sets. 4 - devices changed to drivers for dia
|
||||
version = "18" # 6 - mistification # 5 - updated for SAT data and generic sets. 4 - devices changed to drivers for dia
|
||||
|
||||
# self.sendtodb("version", version, 0)
|
||||
thread.start_new_thread(self.registerThread, ())
|
||||
@@ -331,14 +331,57 @@ class meshifyMain():
|
||||
|
||||
# start the debug thread:
|
||||
thread.start_new_thread(self.debugThread, ())
|
||||
def quick_message(client, userdata, msg):
|
||||
print("In quick message")
|
||||
print(msg.payload.decode("UTF-8"))
|
||||
with open("mqtt.json", "w+") as m:
|
||||
newCreds = {
|
||||
"clientId": self.mac,
|
||||
"username": json.loads(msg.payload.decode("UTF-8"))["credentialsValue"],
|
||||
"password": ""
|
||||
}
|
||||
json.dump(newCreds, m)
|
||||
client.disconnect()
|
||||
|
||||
def quick_connect(mosq, userdata, rc):
|
||||
print("connect quickly")
|
||||
mosq.subscribe("/provision/response", 1)
|
||||
prov_creds = {}
|
||||
with open("provision.json", "r") as prov:
|
||||
try:
|
||||
prov_creds = json.load(prov, encoding="utf-8")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
mosq.publish("/provision/request", json.dumps(prov_creds),1)
|
||||
|
||||
|
||||
|
||||
# set up placeholder for self.mqtt
|
||||
try:
|
||||
print("GETTING CREDS")
|
||||
clientData = {}
|
||||
with open("mqtt.json", "r") as creds:
|
||||
clientData = json.load(creds)
|
||||
except:
|
||||
clientData = {"clientId": mac, "username": "admin", "password": "columbus"}
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("Error getting credentials from file trying to provision credentials")
|
||||
|
||||
print("in file provision.json")
|
||||
try:
|
||||
c = paho.Client(client_id="provision", clean_session=True)
|
||||
print("in paho client for provisioning")
|
||||
#c.username_pw_set("provision", "")
|
||||
c.on_connect = quick_connect
|
||||
c.on_message = quick_message
|
||||
c.connect(broker, port, keepalive=60)
|
||||
c.loop_forever()
|
||||
with open("mqtt.json", "r") as m:
|
||||
clientData = json.load(m)
|
||||
|
||||
del c
|
||||
except Exception as e:
|
||||
print("error in provisions")
|
||||
print(e)
|
||||
#with open("mqtt.json", "w+") as creds:
|
||||
#json.dump(clientData, creds)
|
||||
self.mqtt = paho.Client(client_id=clientData["clientId"], clean_session=True)
|
||||
@@ -1171,16 +1214,18 @@ class meshifyMain():
|
||||
print("error understanding the mqtt message")
|
||||
|
||||
def on_message(self, mosq, obj, msg):
|
||||
print("!!!!!!! ON MESSAGE !!!!!!!")
|
||||
print(msg.topic)
|
||||
print(msg.payload)
|
||||
|
||||
try:
|
||||
print("!!!!!!! ON MESSAGE !!!!!!!")
|
||||
print(msg.topic)
|
||||
print(msg.payload)
|
||||
if "rpc" in msg.topic:
|
||||
payload = {}
|
||||
payload["msgId"] = msg.topic.split("/")[-1]
|
||||
jpayload = json.loads(msg.payload)
|
||||
payload[jpayload["method"]] = jpayload["params"]["value"]
|
||||
msg.payload = json.dumps(payload)
|
||||
|
||||
self.sets(msg.payload)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@@ -27,7 +27,7 @@ class start(threading.Thread):
|
||||
print self.deviceName
|
||||
mac2 = mac.replace(":", "")
|
||||
self.mac = mac2.upper()
|
||||
self.version = "17" #hp device management
|
||||
self.version = "18" #hp device management
|
||||
self.finished = threading.Event()
|
||||
|
||||
threading.Thread.start(self)
|
||||
@@ -56,7 +56,7 @@ class start(threading.Thread):
|
||||
|
||||
|
||||
try:
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
|
||||
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID.lower(), channel)
|
||||
print topic
|
||||
if channel == "files":
|
||||
#for the file structure I had to take off the " " around the value
|
||||
@@ -71,6 +71,27 @@ class start(threading.Thread):
|
||||
def run(self):
|
||||
#on startup send the version number
|
||||
self.sendtodb("version", str(self.version), 0)
|
||||
|
||||
if os.path.isfile('/root/python_firmware/drivers/device_base.py'):
|
||||
print "found new device_base file"
|
||||
os.system("/bin/mv -f /root/python_firmware/drivers/device_base.py /root/python_firmware/device_base.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/device_base.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/device_base.pyc")
|
||||
|
||||
if os.path.isfile('/root/python_firmware/drivers/meshifyData.py'):
|
||||
print "found new meshifyData file"
|
||||
os.system("/bin/mv -f /root/python_firmware/drivers/meshifyData.py /root/python_firmware/meshifyData/meshifyData.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/meshifyData.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/meshifyData.pyc")
|
||||
|
||||
if os.path.isfile('/root/python_firmware/drivers/main.py'):
|
||||
print "found new main.py file"
|
||||
os.system("/bin/mv -f /root/python_firmware/drivers/main.py /root/python_firmware/main.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/main.py")
|
||||
os.system("/bin/rm -f /root/python_firmware/drivers/main.pyc")
|
||||
time.sleep(0.5)
|
||||
os.system('/root/reboot')
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.mainMeshify_hb('hb', 'On')
|
||||
|
||||
@@ -288,5 +288,6 @@
|
||||
"00:00:01:00:00:23": "Kelly #1",
|
||||
"00:00:01:00:00:24": "Kelly #2",
|
||||
"00:00:01:00:00:25": "Kelly #3",
|
||||
"02:42:ac:11:00:04": "RPi Test Device"
|
||||
"02:42:ac:11:00:04": "RPi Test Device",
|
||||
"b8:27:eb:d6:9e:0d": "piflow test"
|
||||
}
|
||||
@@ -27,7 +27,7 @@ class start(threading.Thread):
|
||||
print self.deviceName
|
||||
mac2 = mac.replace(":", "")
|
||||
self.mac = mac2.upper()
|
||||
self.version = "17" #mistification #added Nodes in v5
|
||||
self.version = "18" #mistification #added Nodes in v5
|
||||
self.finished = threading.Event()
|
||||
|
||||
threading.Thread.start(self)
|
||||
|
||||
@@ -480,6 +480,7 @@ class ModbusChannel(Channel):
|
||||
self.transform_fn = transform_fn
|
||||
self.unit_number = unit_number
|
||||
self.instrument = minimalmodbus.Instrument('/dev/ttyS0', self.unit_number)
|
||||
self.instrument.handle_local_echo = True
|
||||
self.scaling= scaling
|
||||
|
||||
def read(self):
|
||||
@@ -491,12 +492,19 @@ class ModbusChannel(Channel):
|
||||
log.info(e)
|
||||
return None
|
||||
|
||||
elif self.data_type == "INTEGER" or self.data_type == "STRING":
|
||||
elif self.data_type == "INTEGER":
|
||||
try:
|
||||
read_value = self.instrument.read_register(self.register_number, self.scaling, 4)
|
||||
except IOError as e:
|
||||
log.info(e)
|
||||
return None
|
||||
elif self.data_type == "STRING":
|
||||
try:
|
||||
read_value = self.instrument.read_string(self.register_number, self.channel_size, 4)
|
||||
read_value = ''.join([i if 0 < ord(i) < 128 else '' for i in read_value])
|
||||
except IOError as e:
|
||||
log.info(e)
|
||||
return None
|
||||
read_value = self.transform_fn(read_value)
|
||||
return read_value
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from device_base import deviceBase
|
||||
import persistence
|
||||
from utilities import get_public_ip_address, get_private_ip_address
|
||||
from file_logger import filelogger as log
|
||||
from sendToMA import send
|
||||
"""import RPi.GPIO as GPIO
|
||||
|
||||
Relay_Ch1 = 26
|
||||
@@ -56,6 +57,7 @@ if not PERSIST:
|
||||
'yesterday_total_midnight_totalizer_3': 0
|
||||
}
|
||||
persistence.store(PERSIST, 'persist.json')
|
||||
|
||||
"""
|
||||
try:
|
||||
if time.time() - PERSIST['state_timer'] >= 60:
|
||||
@@ -103,7 +105,7 @@ class start(threading.Thread, deviceBase):
|
||||
mqtt=mqtt, Nodes=Nodes)
|
||||
|
||||
self.daemon = True
|
||||
self.version = "29"
|
||||
self.version = "31"
|
||||
self.finished = threading.Event()
|
||||
self.force_send = False
|
||||
self.public_ip_address = ""
|
||||
@@ -212,7 +214,7 @@ class start(threading.Thread, deviceBase):
|
||||
payload["values"]["yesterday_" + chan.mesh_name] = yesterday_total
|
||||
elif chan.mesh_name == "volume_flow" and not PERSIST['drive_enabled']:
|
||||
payload["values"][chan.mesh_name] = val
|
||||
if chan.value > 0:
|
||||
if val > 0:
|
||||
payload["values"]["run_status"] = "Running"
|
||||
if not self.rts.runs[self.rts.todayString]["run_" + str(self.rts.currentRun)]["start"]:
|
||||
self.rts.startRun()
|
||||
@@ -247,12 +249,13 @@ class start(threading.Thread, deviceBase):
|
||||
|
||||
except Exception as e:
|
||||
log.warning("An error occured: {}".format(e))
|
||||
time.sleep(3)
|
||||
#time.sleep(3)
|
||||
if (now - self.public_ip_address_last_checked) > IP_CHECK_PERIOD:
|
||||
self._check_ip_address()
|
||||
payload["values"]["public_ip_address"] = self.public_ip_address
|
||||
payload["values"]["private_ip_address"] = self.private_ip_address
|
||||
self.sendToTB(json.dumps(payload))
|
||||
send(payload)
|
||||
attribute_payload = {
|
||||
"latestReportTime": round(time.time()/SEND_PERIOD)*SEND_PERIOD*1000
|
||||
}
|
||||
|
||||
@@ -58,12 +58,15 @@ else:
|
||||
ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('byte_order', 4914, 'INTEGER', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('device_name', 7237, 'STRING', 100, 3600,channel_size=5, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('serial_number', 7002, 'STRING', 100, 3600,channel_size=6, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('remote_start', 0000, 'INTEGER', 1, 86400, channel_size=1, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes),
|
||||
ModbusChannel('run_status', 772, 'INTEGER', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes),
|
||||
ModbusChannel('frequency', 784, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=2 ),
|
||||
ModbusChannel('current', 783, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=1 ),
|
||||
ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a),
|
||||
ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b),
|
||||
ModbusChannel('fault_a', 815, 'INTEGER', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a),
|
||||
ModbusChannel('fault_b', 816, 'INTEGER', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b),
|
||||
ModbusChannel('pid_ref', 791, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1),
|
||||
ModbusChannel('pid_feedback', 792, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1),
|
||||
ModbusChannel('motor_rated_current', 4896, 'INTEGER', 300, 86400, channel_size=1, unit_number=drive_unit_number,scaling=1),
|
||||
@@ -79,6 +82,9 @@ else:
|
||||
ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
|
||||
ModbusChannel('byte_order', 4914, 'INTEGER', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('device_name', 7237, 'STRING', 100, 3600,channel_size=5, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('serial_number', 7002, 'STRING', 100, 3600,channel_size=6, unit_number=flowmeter_unit_number),
|
||||
ModbusChannel('remote_start', 0000, 'BOOL', 1, 86400, channel_size=1, unit_number=flowmeter_unit_number)
|
||||
]
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"driverFileName":"PiFlow.py",
|
||||
"deviceName":"piflow",
|
||||
"driverId":"0280",
|
||||
"releaseVersion":"29",
|
||||
"releaseVersion":"31",
|
||||
"files": {
|
||||
"file1":"PiFlow.py",
|
||||
"file2":"Channel.py",
|
||||
@@ -11,7 +11,9 @@
|
||||
"file4":"Tags.py",
|
||||
"file5":"utilities.py",
|
||||
"file6":"persistence.py",
|
||||
"file7":"runtimeStats.py"
|
||||
"file7":"runtimeStats.py",
|
||||
"file8": "modbusTester.py",
|
||||
"file9": "sendToMA.py"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +1,355 @@
|
||||
import minimalmodbus
|
||||
|
||||
import time, json
|
||||
minimalmodbus.BAUDRATE = 9600
|
||||
minimalmodbus.STOPBITS = 1
|
||||
address = 123
|
||||
|
||||
instrument = minimalmodbus.Instrument('/dev/ttyS0', address) #device, modbus slave address
|
||||
instrument.debug = True
|
||||
for _ in range(3):
|
||||
try:
|
||||
value = instrument.read_float(3873) #register -1 for float
|
||||
print("Flow Rate from Flow Meter: {}".format(value))
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
fmaddress = 110
|
||||
daddress = 1
|
||||
|
||||
with open("/root/python_firmware/persist.json", "r") as f:
|
||||
temp = json.load(f)
|
||||
daddress = temp.get("drive", 1)
|
||||
fmaddress = temp.get("flowmeter", 247)
|
||||
|
||||
|
||||
|
||||
def volume_units(vunit):
|
||||
units = {
|
||||
0: "cm cubed/s",
|
||||
1: "cm cubed/min",
|
||||
2: "cm cubed/h",
|
||||
3: "cm cubed/d",
|
||||
4: "dm cubed/s",
|
||||
5: "dm cubed/min",
|
||||
6: "dm cubed/h",
|
||||
7: "dm cubed/d",
|
||||
8: "m cubed/s",
|
||||
9: "m cubed/min",
|
||||
10: "m cubed/h",
|
||||
11: "m cubed/d",
|
||||
12: "ml/s",
|
||||
13: "ml/min",
|
||||
14: "ml/h",
|
||||
15: "ml/d",
|
||||
16: "l/s",
|
||||
17: "l/min",
|
||||
18: "l/h (+)",
|
||||
19: "l/d",
|
||||
20: "hl/s",
|
||||
21: "hl/min",
|
||||
22: "hl/h",
|
||||
23: "hl/d",
|
||||
24: "Ml/s",
|
||||
25: "Ml/min",
|
||||
26: "Ml/h",
|
||||
27: "Ml/d",
|
||||
32: "af/s",
|
||||
33: "af/min",
|
||||
34: "af/h",
|
||||
35: "af/d",
|
||||
36: "ft cubed/s",
|
||||
37: "ft cubed/min",
|
||||
38: "ft cubed/h",
|
||||
39: "ft cubed/d",
|
||||
40: "fl oz/s (us)",
|
||||
41: "fl oz/min (us)",
|
||||
42: "fl oz/h (us)",
|
||||
43: "fl oz/d (us)",
|
||||
44: "gal/s (us)",
|
||||
45: "gal/min (us)",
|
||||
46: "gal/h (us)",
|
||||
47: "gal/d (us)",
|
||||
48: "Mgal/s (us)",
|
||||
49: "Mgal/min (us)",
|
||||
50: "Mgal/h (us)",
|
||||
51: "Mgal/d (us)",
|
||||
52: "bbl/s (us;liq.)",
|
||||
53: "bbl/min (us;liq.)",
|
||||
54: "bbl/h (us;liq.)",
|
||||
55: "bbl/d (us;liq.)",
|
||||
56: "bbl/s (us;beer)",
|
||||
57: "bbl/min (us;beer)",
|
||||
58: "bbl/h (us;beer)",
|
||||
59: "bbl/d (us;beer)",
|
||||
60: "bbl/s (us;oil)",
|
||||
61: "bbl/min (us;oil)",
|
||||
62: "bbl/h (us;oil)",
|
||||
63: "bbl/d (us;oil)",
|
||||
64: "bbl/s (us;tank)",
|
||||
65: "bbl/min (us;tank)",
|
||||
66: "bbl/h (us;tank)",
|
||||
67: "bbl/d (us;tank)",
|
||||
68: "gal/s (imp)",
|
||||
69: "gal/min (imp)",
|
||||
70: "gal/h (imp)",
|
||||
71: "gal/d (imp)",
|
||||
72: "Mgal/s (imp)",
|
||||
73: "Mgal/min (imp)",
|
||||
74: "Mgal/h (imp)",
|
||||
75: "Mgal/d (imp)",
|
||||
76: "bbl/s (imp;beer)",
|
||||
77: "bbl/min (imp;beer)",
|
||||
78: "bbl/h (imp;beer)",
|
||||
79: "bbl/d (imp;beer)",
|
||||
80: "bbl/s (imp;oil)",
|
||||
81: "bbl/min (imp;oil)",
|
||||
82: "bbl/h (imp;oil)",
|
||||
83: "bbl/d (imp;oil)",
|
||||
88: "kgal/s (us)",
|
||||
89: "kgal/min (us)",
|
||||
90: "kgal/h (us)",
|
||||
91: "kgal/d (us)",
|
||||
92: "MMft cubed/s",
|
||||
93: "MMft cubed/min",
|
||||
94: "MMft cubed/h",
|
||||
96: "Mft cubed/d"
|
||||
}
|
||||
return units[vunit]
|
||||
|
||||
def totalizer_units(tunit):
|
||||
|
||||
try:
|
||||
value = instrument.read_float(784) #register -1 for float
|
||||
print("Frequency from Drive: {}".format(value))
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
units = {
|
||||
0: "cm cubed",
|
||||
1: "dm cubed",
|
||||
2: "m cubed",
|
||||
3: "ml",
|
||||
4: "l",
|
||||
5: "hl",
|
||||
6: "Ml Mega",
|
||||
8: "af",
|
||||
9: "ft cubed",
|
||||
10: "fl oz (us)",
|
||||
11: "gal (us)",
|
||||
12: "Mgal (us)",
|
||||
13: "bbl (us;liq.)",
|
||||
14: "bbl (us;beer)",
|
||||
15: "bbl (us;oil)",
|
||||
16: "bbl (us;tank)",
|
||||
17: "gal (imp)",
|
||||
18: "Mgal (imp)",
|
||||
19: "bbl (imp;beer)",
|
||||
20: "bbl (imp;oil)",
|
||||
22: "kgal (us)",
|
||||
23: "Mft cubed",
|
||||
50: "g",
|
||||
51: "kg",
|
||||
52: "t",
|
||||
53: "oz",
|
||||
54: "lb",
|
||||
55: "STon",
|
||||
100: "Nl",
|
||||
101: "Nm cubed",
|
||||
102: "Sm cubed",
|
||||
103: "Sft cubed",
|
||||
104: "Sl",
|
||||
105: "Sgal (us)",
|
||||
106: "Sbbl (us;liq.)",
|
||||
107: "Sgal (imp)",
|
||||
108: "Sbbl (us;oil)",
|
||||
109: "MMSft cubed",
|
||||
110: "Nhl",
|
||||
251: "None"
|
||||
}
|
||||
return units[tunit]
|
||||
|
||||
def int_to_bits(n,x):
|
||||
return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the "0b" part
|
||||
|
||||
def pad_to_x(n,x):
|
||||
while len(n) < x:
|
||||
n = [0] + n
|
||||
return n
|
||||
|
||||
def status_codes(n):
|
||||
|
||||
status_array = int_to_bits(n,16)
|
||||
status_low = {
|
||||
0: "Stopped;",
|
||||
1: "Operating in Forward;",
|
||||
2: "Operating in Reverse;",
|
||||
3: "DC operating;"
|
||||
}
|
||||
status_mid = {
|
||||
0: "",
|
||||
1: "Speed searching;",
|
||||
2: "Accelerating;",
|
||||
3: "At constant speed;",
|
||||
4: "Decelerating;",
|
||||
5: "Decelerating to stop;",
|
||||
6: "H/W OCS;",
|
||||
7: "S/W OCS;",
|
||||
8: "Dwell operating;"
|
||||
}
|
||||
status_high = {
|
||||
0: "Normal state",
|
||||
4: "Warning occurred",
|
||||
8: "Fault occurred"
|
||||
}
|
||||
values = {
|
||||
0: 8,
|
||||
1: 4,
|
||||
2: 2,
|
||||
3: 1
|
||||
}
|
||||
|
||||
stats_low = status_array[12:]
|
||||
stats_mid = status_array[8:12]
|
||||
stats_high = status_array[:4]
|
||||
low = 0
|
||||
mid = 0
|
||||
high = 0
|
||||
for x in range(4):
|
||||
if stats_low[x] == 1:
|
||||
low = low + values[x]
|
||||
if stats_mid[x] == 1:
|
||||
mid = mid + values[x]
|
||||
if stats_high[x] == 1:
|
||||
high = high + values[x]
|
||||
|
||||
return status_low[low] + " " + status_mid[mid] + ' ' + status_high[high]
|
||||
|
||||
def fault_code_a(n):
|
||||
|
||||
fault_code_array = int_to_bits(n,16)
|
||||
|
||||
""" fault = {
|
||||
0: "OCT",
|
||||
1: "OVT",
|
||||
2: "EXT-A",
|
||||
3: "EST",
|
||||
4: "COL",
|
||||
5: "GFT",
|
||||
6: "OHT",
|
||||
7: "ETH",
|
||||
8: "OLT",
|
||||
9: "Reserved",
|
||||
10: "EXT-B",
|
||||
11: "EEP",
|
||||
12: "FAN",
|
||||
13: "POT",
|
||||
14: "IOLT",
|
||||
15: "LVT"
|
||||
} """
|
||||
fault = {
|
||||
0: "Overload Trip",
|
||||
1: "Underload Trip",
|
||||
2: "Inverter Overload Trip",
|
||||
3: "E-Thermal Trip",
|
||||
4: "Ground Fault Trip",
|
||||
5: "Output Image Trip",
|
||||
6: "Inmput Imaging Trip",
|
||||
7: "Reserved",
|
||||
8: "Reserved",
|
||||
9: "NTC Trip",
|
||||
10: "Overcurrent Trip",
|
||||
11: "Overvoltage Trip",
|
||||
12: "External Trip",
|
||||
13: "Arm Short",
|
||||
14: "Over Heat Trip",
|
||||
15: "Fuse Open Trip"
|
||||
}
|
||||
|
||||
faults = []
|
||||
counter = 15
|
||||
for x in range(16):
|
||||
if fault_code_array[x] == 1:
|
||||
faults = [fault[counter]] + faults
|
||||
counter = counter - 1
|
||||
return ' '.join(faults)
|
||||
|
||||
def fault_code_b(n):
|
||||
|
||||
fault_code_array = int_to_bits(n,8)
|
||||
|
||||
""" fault = {
|
||||
0: "COM",
|
||||
1: "Reserved",
|
||||
2: "NTC",
|
||||
3: "REEP",
|
||||
4: "OC2",
|
||||
5: "NBR",
|
||||
6: "SAFA",
|
||||
7: "SAFB"
|
||||
} """
|
||||
fault = {
|
||||
0: "Reserved",
|
||||
1: "Reserved",
|
||||
2: "Reserved",
|
||||
3: "FAN Trip",
|
||||
4: "Reserved",
|
||||
5: "Reserved",
|
||||
6: "Pre PID Fail",
|
||||
7: "Bad contact at basic I/O board",
|
||||
8: "External Brake Trip",
|
||||
9: "No Motor Trip",
|
||||
10: "Bad Option Card",
|
||||
11: "Reserved",
|
||||
12: "Reserved",
|
||||
13: "Reserved",
|
||||
14: "Pre Over Heat Trip",
|
||||
15: "Reserved"
|
||||
}
|
||||
|
||||
faults = []
|
||||
counter = 7
|
||||
for x in range(8):
|
||||
if fault_code_array[x] == 1:
|
||||
faults = [fault[counter]] + faults
|
||||
counter = counter - 1
|
||||
return ' '.join(faults)
|
||||
|
||||
registers = [
|
||||
('volume_flow', 3873, 'FLOAT', 10, 3600,2, fmaddress, None ),
|
||||
('totalizer_1', 2609, 'FLOAT', 100, 3600,2, fmaddress, None ),
|
||||
('totalizer_2', 2809, 'FLOAT', 100, 3600,2, fmaddress, None ),
|
||||
('totalizer_3', 3009, 'FLOAT', 100, 3600,2, fmaddress, None ),
|
||||
('volume_flow_units', 2102, 'INTEGER', 1,86400,1, fmaddress, volume_units),
|
||||
('totalizer_1_units', 4603, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
|
||||
('totalizer_2_units', 4604, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
|
||||
('totalizer_3_units', 4605, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
|
||||
('byte_order', 4914, 'INTEGER', 100, 3600,2, fmaddress, None),
|
||||
('device_name', 7237, 'STRING', 100, 3600,5, fmaddress, None),
|
||||
('serial_number', 7002, 'STRING', 100, 3600,6, fmaddress, None),
|
||||
('run_status', 772, 'INTEGER', 0, 3600, 1, daddress, status_codes),
|
||||
('frequency', 784, 'INTEGER', 2, 3600, 2, daddress, None),
|
||||
('current', 783, 'INTEGER', 2, 3600, 2, daddress, None),
|
||||
('fault_a', 815, 'INTEGER', 1, 3600, 1, daddress, fault_code_a),
|
||||
('fault_b', 816, 'INTEGER', 1, 3600, 1, daddress, fault_code_b),
|
||||
('pid_ref', 791, 'INTEGER', 5, 3600, 1, daddress, None),
|
||||
('pid_feedback', 792, 'INTEGER', 5, 3600, 1, daddress, None),
|
||||
('motor_rated_current', 4896, 'INTEGER', 300, 86400, 1, daddress, None),
|
||||
('sleep_delay', 4924, 'INTEGER', 5, 86400, 1, daddress, None)
|
||||
]
|
||||
for register in registers:
|
||||
instrument = minimalmodbus.Instrument('/dev/ttyS0', register[6]) #device, modbus slave address
|
||||
instrument.debug = False
|
||||
instrument.handle_local_echo = True
|
||||
if register[2] == "FLOAT":
|
||||
try:
|
||||
value = instrument.read_float(registeraddress=register[1], functioncode=4) #register -1 for float
|
||||
if register[7] != None:
|
||||
value = register[7](value)
|
||||
print("{} from {}: {}".format(register[0],register[6],value))
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
#time.sleep(1)
|
||||
elif register[2] == "INTEGER":
|
||||
try:
|
||||
value = instrument.read_register(registeraddress=register[1],functioncode=4) #register -1 for float
|
||||
if register[7] != None:
|
||||
value = register[7](value)
|
||||
print("{} from {}: {}".format(register[0],register[6],value))
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
#time.sleep(1)
|
||||
elif register[2] == "STRING":
|
||||
try:
|
||||
value = instrument.read_string(register[1], register[5], functioncode=4)
|
||||
value = ''.join([i if 0 < ord(i) < 128 else '' for i in value])
|
||||
if register[7] != None:
|
||||
value = register[7](value)
|
||||
print("{} from {}: {}".format(register[0],register[6],value))
|
||||
except Exception as e:
|
||||
print("Error: {}".format(e))
|
||||
#time.sleep(1)
|
||||
|
||||
|
||||
45
meshifyDrivers/piflow/sendToMA.py
Normal file
45
meshifyDrivers/piflow/sendToMA.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import client as paho
|
||||
import json
|
||||
from uuid import getnode as get_mac
|
||||
def get_mac_address():
|
||||
try:
|
||||
provision = {}
|
||||
deviceMap = {}
|
||||
with open("/root/python_firmware/provision.json", "r") as f:
|
||||
provision = json.load(f)
|
||||
with open("/root/python_firmware/drivers/deviceMap.json", "r") as f:
|
||||
deviceMap = json.load(f)
|
||||
if provision and deviceMap:
|
||||
deviceName = provision.get("deviceName")
|
||||
if deviceName:
|
||||
mac = deviceMap.keys()[deviceMap.values().index(deviceName)]
|
||||
if mac:
|
||||
return mac
|
||||
except Exception as e:
|
||||
print("Didn't find mac in deviceMap: {}".format(e))
|
||||
try:
|
||||
mac = get_mac()
|
||||
mac = ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))
|
||||
return str(mac).lower()
|
||||
except:
|
||||
mac = "12:34:56:78:91:23"
|
||||
return mac
|
||||
mac = get_mac_address()
|
||||
|
||||
|
||||
topic_base = "meshify/db/194/_/piflow/" + mac + ":01:99/"
|
||||
topic_meshify = "meshify/db/194/_/mainHP/" + mac + ":00:00/connected"
|
||||
c = paho.Client(client_id=mac, clean_session=True)
|
||||
c.username_pw_set("admin", "columbus")
|
||||
c.will_set(topic_meshify, json.dumps([{"value": False}]), 2)
|
||||
c.connect("mq194.imistaway.net", 1883, keepalive=900)
|
||||
c.loop_start()
|
||||
|
||||
def send(payload):
|
||||
c.publish(topic_meshify, json.dumps([{"value": True}]), 1)
|
||||
for key,value in payload["values"].items():
|
||||
topic = topic_base + key
|
||||
print(topic)
|
||||
print(value)
|
||||
c.publish(topic, json.dumps([{"value": value}]), 1)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
{
|
||||
"files": {
|
||||
"file3": "channel.py",
|
||||
"file3": "Channel.py",
|
||||
"file2": "utilities.py",
|
||||
"file1": "transferlite.py",
|
||||
"file4": "file_logger.py"
|
||||
"file4": "file_logger.py",
|
||||
"file5": "sendToMA.py",
|
||||
"file6": "persistence.py"
|
||||
},
|
||||
"deviceName": "transferlite",
|
||||
"driverId": "0230",
|
||||
"releaseVersion": "5",
|
||||
"releaseVersion": "7",
|
||||
"driverFileName": "transferlite.py"
|
||||
}
|
||||
45
meshifyDrivers/transferlite/sendToMA.py
Normal file
45
meshifyDrivers/transferlite/sendToMA.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import client as paho
|
||||
import json
|
||||
from uuid import getnode as get_mac
|
||||
def get_mac_address():
|
||||
try:
|
||||
provision = {}
|
||||
deviceMap = {}
|
||||
with open("/root/python_firmware/provision.json", "r") as f:
|
||||
provision = json.load(f)
|
||||
with open("/root/python_firmware/drivers/deviceMap.json", "r") as f:
|
||||
deviceMap = json.load(f)
|
||||
if provision and deviceMap:
|
||||
deviceName = provision.get("deviceName")
|
||||
if deviceName:
|
||||
mac = deviceMap.keys()[deviceMap.values().index(deviceName)]
|
||||
if mac:
|
||||
return mac
|
||||
except Exception as e:
|
||||
print("Didn't find mac in deviceMap: {}".format(e))
|
||||
try:
|
||||
mac = get_mac()
|
||||
mac = ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))
|
||||
return str(mac).lower()
|
||||
except:
|
||||
mac = "12:34:56:78:91:23"
|
||||
return mac
|
||||
mac = get_mac_address()
|
||||
|
||||
|
||||
topic_base = "meshify/db/194/_/transferlite/" + mac + ":01:99/"
|
||||
topic_meshify = "meshify/db/194/_/mainHP/" + mac + ":00:00/connected"
|
||||
c = paho.Client(client_id=mac, clean_session=True)
|
||||
c.username_pw_set("admin", "columbus")
|
||||
c.will_set(topic_meshify, json.dumps([{"value": False}]), 2)
|
||||
c.connect("mq194.imistaway.net", 1883, keepalive=900)
|
||||
c.loop_start()
|
||||
|
||||
def send(payload):
|
||||
c.publish(topic_meshify, json.dumps([{"value": True}]), 1)
|
||||
for key,value in payload["values"].items():
|
||||
topic = topic_base + key
|
||||
print(topic)
|
||||
print(value)
|
||||
c.publish(topic, json.dumps([{"value": value}]), 1)
|
||||
|
||||
@@ -10,7 +10,7 @@ from device_base import deviceBase
|
||||
from channel import PLCChannel, read_tag, write_tag,TAG_DATAERROR_SLEEPTIME
|
||||
from utilities import get_public_ip_address
|
||||
from file_logger import filelogger as log
|
||||
|
||||
from sendToMA import send
|
||||
|
||||
_ = None
|
||||
log.info("transferlite startup")
|
||||
@@ -45,6 +45,7 @@ IP_CHECK_PERIOD = 60
|
||||
WATCHDOG_ENABLE = True
|
||||
WATCHDOG_CHECK_PERIOD = 60
|
||||
WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending the watchdog status
|
||||
REPORT_PERIOD = 600
|
||||
PLC_IP_ADDRESS = "192.168.1.10"
|
||||
CHANNELS = [
|
||||
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd", "FT01_Flowmeter_BPD", "REAL", 100.0, 600),
|
||||
@@ -81,7 +82,7 @@ class start(threading.Thread, deviceBase):
|
||||
mqtt=mqtt, Nodes=Nodes)
|
||||
|
||||
self.daemon = True
|
||||
self.version = "5"
|
||||
self.version = "7"
|
||||
self.finished = threading.Event()
|
||||
self.force_send = False
|
||||
self.public_ip_address = ""
|
||||
@@ -116,17 +117,18 @@ class start(threading.Thread, deviceBase):
|
||||
now = time.time()
|
||||
if self.force_send:
|
||||
log.warning("FORCE SEND: TRUE")
|
||||
if int(time.time()) % 600 == 0 or self.force_send:
|
||||
if int(time.time()) % REPORT_PERIOD == 0 or self.force_send:
|
||||
if self.force_send:
|
||||
payload = {"ts": time.time()*1000, "values": {}}
|
||||
else:
|
||||
payload = {"ts": round(time.time()/600)*600*1000, "values": {}}
|
||||
payload = {"ts": round(time.time()/REPORT_PERIOD)*REPORT_PERIOD*1000, "values": {}}
|
||||
for chan in CHANNELS:
|
||||
val = chan.read()
|
||||
payload["values"][chan.mesh_name] = val
|
||||
payload["values"]["public_ip_address"] = self.public_ip_address
|
||||
self.sendToTB(json.dumps(payload))
|
||||
self.sendToTBAttributes(json.dumps({"latestReportTime": round(time.time()/600)*600*1000}))
|
||||
send(payload)
|
||||
self.sendToTBAttributes(json.dumps({"latestReportTime": round(time.time()/REPORT_PERIOD)*REPORT_PERIOD*1000}))
|
||||
|
||||
# print("transferlite driver still alive...")
|
||||
if self.force_send:
|
||||
|
||||
290
migration.csv
Normal file
290
migration.csv
Normal file
@@ -0,0 +1,290 @@
|
||||
mac,name,deviceType,migrated
|
||||
c4:93:00:0e:d5:03,Nail Ranch 37 SR 2-3,advvfdipp,False
|
||||
c4:93:00:0c:68:36,Wrage 21 SR 2-2,advvfdipp,False
|
||||
c4:93:00:08:d0:11,Wrage 28 SR 2-2,advvfdipp,False
|
||||
b8:27:eb:46:8d:7d,Free 40 WS 2-2,piflow,False
|
||||
b8:27:eb:78:03:88,Wilkinson 1 WS 1-9,piflow,False
|
||||
b8:27:eb:86:b6:dc,Wilkinson 1 WS 1-10B,piflow,False
|
||||
b8:27:eb:06:b1:94,Wilkinson 39 WS 1-3,piflow,False
|
||||
b8:27:eb:02:2f:f0,Wilkinson 4 WS 1-10,piflow,False
|
||||
b8:27:eb:c1:ac:f5,Horton 34 WS 10-5,piflow,False
|
||||
c4:93:00:0a:89:f5,Bowling WW 4-1,flowmonitor,False
|
||||
c4:93:00:08:d0:65,Banay WW 7-1,flowmonitor,False
|
||||
c4:93:00:0e:e9:c1,Banay WW 5-1,flowmonitor,False
|
||||
c4:93:00:09:51:ce,Bowling WW 37-1,flowmonitor,False
|
||||
c4:93:00:0c:68:57,Banay WW 504,flowmonitor,False
|
||||
c4:93:00:0d:f2:68,Banay WW 18 #4,flowmonitor,False
|
||||
c4:93:00:0d:bb:48,Banay WW 18 #9,flowmonitor,False
|
||||
00:00:01:00:00:05,Windham 108-1,plcfreshwater,False
|
||||
00:00:01:00:00:07,Windham 108-3,plcfreshwater,False
|
||||
c4:93:00:08:d4:49,Wrage 32 SR 1-1,advvfdipp,False
|
||||
b8:27:eb:68:43:70,LimeQuest 5 WS 10-10,piflow,False
|
||||
00:00:00:00:00:02,Florence WW #2,plcfreshwater,False
|
||||
00:00:00:00:00:03,Florence WW #1,plcfreshwater,False
|
||||
00:00:00:00:00:11,Madelyn Kate #3 WW,plcfreshwater,False
|
||||
00:00:00:00:00:14,Jessica WW #3,plcfreshwater,False
|
||||
00:00:01:00:00:01,Windham 108-7,plcfreshwater,False
|
||||
00:00:01:00:00:02,Windham 108-6,plcfreshwater,False
|
||||
00:00:01:00:00:03,Windham 108-5,plcfreshwater,False
|
||||
00:00:01:00:00:04,Windham 107-1,plcfreshwater,False
|
||||
00:00:01:00:00:08,Windham 107-2,plcfreshwater,False
|
||||
00:00:01:00:00:09,Windham 108-8,plcfreshwater,False
|
||||
00:00:01:00:00:10,Windham 108-10,plcfreshwater,False
|
||||
00:00:01:00:00:11,Windham 108-2,plcfreshwater,False
|
||||
00:00:01:00:00:12,Windham 108-9,plcfreshwater,False
|
||||
00:00:00:00:00:18,Jessica WW #7,plcfreshwater,False
|
||||
c4:93:00:0d:f1:6c,Faudree Frac Pit Pump #1,advvfdipp,False
|
||||
c4:93:00:0d:f2:8c,Faudree Frac Pit Pump #2,advvfdipp,False
|
||||
c4:93:00:03:af:34,Wilkinson Ranch 34 SR 2-2,ipp,False
|
||||
c4:93:00:05:dd:a2,Nail Ranch 2 SR 3-3,advvfdipp,False
|
||||
c4:93:00:03:54:c5,Nail Ranch 38 SR 2-3,advvfdipp,False
|
||||
c4:93:00:03:69:c8,Nail Ranch 25 SR 2-1,advvfdipp,False
|
||||
c4:93:00:05:dd:ed,Nail Ranch 28 SR 3-3,advvfdipp,False
|
||||
c4:93:00:03:56:7b,Nail Ranch 38 SR 1-3,advvfdipp,False
|
||||
c4:93:00:03:6b:12,Nail Ranch 3 SR 3-2,advvfdipp,False
|
||||
c4:93:00:03:7f:b2,Nail Ranch 28 SR 2-2,advvfdipp,False
|
||||
c4:93:00:05:85:1f,Nail Ranch 28 SR 1-1,advvfdipp,False
|
||||
c4:93:00:03:6b:2d,Guitar 22 SR 3-3,advvfdipp,False
|
||||
c4:93:00:0c:d2:29,Wilkinson Ranch 33 SR 2-2,advvfdipp,False
|
||||
c4:93:00:0c:67:af,Wilkinson Ranch 35 SR 1-1,advvfdipp,False
|
||||
c4:93:00:0c:aa:75,Wilkinson Ranch 1 SR 2-2,advvfdipp,False
|
||||
c4:93:00:0d:f3:55,Limequest Transfer Lite,transferlite,False
|
||||
c4:93:00:0d:f2:5c,S. Wilkinson Transfer Lite,m1,False
|
||||
c4:93:00:0d:f2:8f,Nail Ranch 2 SR 2-2,advvfdipp,False
|
||||
c4:93:00:0d:f0:ca,Horton Transfer Lite,transferlite,False
|
||||
c4:93:00:0d:f2:b0,South Wilkinson Transfer #2,transferlite,False
|
||||
b8:27:eb:16:f0:64,Wilkinson 39 WS 1-5,piflow,False
|
||||
b8:27:eb:d8:64:a6,Wilkinson 39 WS 1-4,piflow,False
|
||||
b8:27:eb:5a:1c:1e,Wilkinson 39 WS 1-2,piflow,False
|
||||
b8:27:eb:a0:e9:f9,Free 40 WS 1-2,piflow,False
|
||||
b8:27:eb:da:8d:ea,Wilkinson 39 WS 1-1,piflow,False
|
||||
b8:27:eb:9a:2e:f0,Free 32 WS 3-10C,piflow,False
|
||||
b8:27:eb:06:d1:c0,Free 40 WS 5-6,piflow,False
|
||||
b8:27:eb:75:d2:6a,Free 40 WS 1-4,piflow,False
|
||||
b8:27:eb:e0:0b:2c,Free 40 WS 1-6,piflow,False
|
||||
b8:27:eb:01:75:8e,Free 32 WS 3-10A,piflow,False
|
||||
b8:27:eb:06:2e:17,Wilkinson 34 WS 9-10,piflow,False
|
||||
b8:27:eb:6d:7f:6c,Wilkinson 33 WS 10-3A,piflow,False
|
||||
b8:27:eb:7d:e9:f8,Wilkinson 33 WS 10-3B,piflow,False
|
||||
b8:27:eb:1c:c4:49,Wilkinson 33 WS 10-1B,piflow,False
|
||||
b8:27:eb:f9:71:92,Wilkinson 33 WS 6-7,piflow,False
|
||||
b8:27:eb:d4:cb:e4,Free 32 WS 3-10B,piflow,False
|
||||
b8:27:eb:0e:6a:13,LimeQuest 5 WS 9-9,piflow,False
|
||||
b8:27:eb:2b:d6:59,LimeQuest 5 WS 6-8,piflow,False
|
||||
b8:27:eb:92:a0:18,LimeQuest 5 WS 2-4,piflow,False
|
||||
b8:27:eb:92:65:df,LimeQuest 5 WS 8-5,piflow,False
|
||||
b8:27:eb:5c:4e:e4,LimeQuest 5 WS 7-5,piflow,False
|
||||
b8:27:eb:0e:2e:f2,LimeQuest 5 WS 4-7,piflow,False
|
||||
b8:27:eb:c4:7e:50,Horton 23 WS 5-6,piflow,False
|
||||
b8:27:eb:1e:a1:f7,Horton 23 WS 8-6,piflow,False
|
||||
b8:27:eb:fa:2d:73,Horton 23 WS 6-6,piflow,False
|
||||
b8:27:eb:bd:3b:55,Horton 34 WS 1-2,piflow,False
|
||||
b8:27:eb:a7:7f:6f,Horton 23 WS 5-2,piflow,False
|
||||
b8:27:eb:2f:c5:8c,Horton 23 WS 5-5,piflow,False
|
||||
b8:27:eb:e9:c5:7d,Wilkinson 37 WS 1-9B,piflow,False
|
||||
b8:27:eb:96:a0:2d,Wilkinson 39 WS 2-2,piflow,False
|
||||
c4:93:00:0d:bb:42,Wilkinson 37 WS 1-8,advvfdipp,False
|
||||
b8:27:eb:b8:9b:a7,Wilkinson 1 WS 9-4B,piflow,False
|
||||
c4:93:00:0d:bb:45,ToolBox South,advvfdipp,False
|
||||
c4:93:00:08:cf:c0,Carmanita WW 12-2,flowmonitor,False
|
||||
c4:93:00:08:cf:ba,Carmanita WW 12-1,flowmonitor,False
|
||||
c4:93:00:08:cf:0c,Banay North Frac Pit,pondlevel,False
|
||||
c4:93:00:08:d4:31,Banay South Frac Pit,pondlevel,False
|
||||
c4:93:00:0a:8a:0d,Banay South Inlet,promagmbs,False
|
||||
c4:93:00:09:4c:ee,Banay WW 18 #3,flowmonitor,False
|
||||
c4:93:00:0b:0c:d5,Carmanita WW 12-3,flowmonitor,False
|
||||
c4:93:00:0c:aa:ff,Banay WW 8-5,flowmonitor,False
|
||||
c4:93:00:0d:f1:5d,Banay WW 8-2,flowmonitor,False
|
||||
c4:93:00:0d:e8:9f,Banay WW 6-1,flowmonitor,False
|
||||
c4:93:00:0d:f1:87,Banay WW 18 #10,flowmonitor,False
|
||||
c4:93:00:03:7c:dc,Carmanita WW 12-4,flowmonitor,False
|
||||
c4:93:00:0d:f5:56,Banay WW 18 #1,flowmonitor,False
|
||||
00:00:00:00:00:04,Caden WW #1,plcfreshwater,False
|
||||
00:00:00:00:00:05,Caden WW #2,plcfreshwater,False
|
||||
00:00:00:00:00:06,Caden WW #3,plcfreshwater,False
|
||||
00:00:00:00:00:07,Caden WW #4,plcfreshwater,False
|
||||
00:00:00:00:00:09,Lisa WW #1,plcfreshwater,False
|
||||
00:00:00:00:00:08,Caden WW #6,plcfreshwater,False
|
||||
00:00:00:00:00:16,Laurie Gwen WW #1,plcfreshwater,False
|
||||
00:00:00:00:00:10,Jessica WW #4,plcfreshwater,False
|
||||
00:00:00:00:00:12,Jessica WW #1,plcfreshwater,False
|
||||
00:00:00:00:00:13,Jessica WW #2,plcfreshwater,False
|
||||
b8:27:eb:a9:df:e5,Denali East Frac Pit,plcpond,False
|
||||
c4:93:00:0d:f1:c0,Banay WW 8-4,flowmonitor,False
|
||||
00:00:00:00:00:17,Jessica WW #5,plcfreshwater,False
|
||||
c4:93:00:0b:0c:f6,Map Rock Transfer Pump Monitor,dual_flowmeter,False
|
||||
b8:27:eb:aa:8a:53,LimeQuest 5 WS 7-9,piflow,False
|
||||
c4:93:00:09:51:bf,Banay North Pit Inlet #1,m1,False
|
||||
c4:93:00:0d:f2:b9,Banay North Pit Outlet #1,m1,False
|
||||
c4:93:00:0d:f5:44,Yvonne Frac Pit,m1,False
|
||||
b8:27:eb:be:09:91,Denali Frac Pit,dual_flowmeter,False
|
||||
b8:27:eb:df:53:70,Horton 34 WS 1-4,piflow,False
|
||||
00:00:02:00:00:02,Cindy #1,plcfreshwater,False
|
||||
00:00:02:00:00:08,Cindy #3,plcfreshwater,False
|
||||
00:00:02:00:00:11,Cindy #2,plcfreshwater,False
|
||||
00:00:03:00:00:03,Lindsey #3,plcfreshwater,False
|
||||
00:00:02:00:00:09,Elizabeth 1,plcfreshwater,False
|
||||
00:00:02:00:00:13,Railway 12-3,plcfreshwater,False
|
||||
00:00:02:00:00:14,Railway 12-2,plcfreshwater,False
|
||||
00:00:02:00:00:15,Elizabeth B1,plcfreshwater,False
|
||||
00:00:02:00:00:16,Elizabeth B2,plcfreshwater,False
|
||||
00:00:02:00:00:17,Rhonda 1,plcfreshwater,False
|
||||
00:00:02:00:00:18,Sec 46 #1,plcfreshwater,False
|
||||
00:00:02:00:00:19,Cynthia 1,plcfreshwater,False
|
||||
00:00:02:00:00:20,Nancy #2,plcfreshwater,False
|
||||
00:00:02:00:00:21,Nancy #1,plcfreshwater,False
|
||||
00:00:02:00:00:22,Rhonda Pit,plcfreshwater,False
|
||||
00:00:03:00:00:05,Jitterbug 28-1,plcfreshwater,False
|
||||
00:00:03:00:00:06,Reagan #1,plcfreshwater,False
|
||||
00:00:00:00:00:19,Aurora 7,plcfreshwater,False
|
||||
00:00:00:00:00:20,Aurora 8,plcfreshwater,False
|
||||
00:00:00:00:00:21,Aurora 9,plcfreshwater,False
|
||||
00:00:00:00:00:22,Aurora 10,plcfreshwater,False
|
||||
00:00:00:00:00:23,Aurora 11,plcfreshwater,False
|
||||
00:00:00:00:00:24,Aurora 6,plcfreshwater,False
|
||||
00:00:05:00:00:01,RebJean #2,plcfreshwater,False
|
||||
00:00:05:00:00:02,Terri #6,plcfreshwater,False
|
||||
00:00:05:00:00:03,RobJane #2,plcfreshwater,False
|
||||
00:00:05:00:00:04,RobJane #3,plcfreshwater,False
|
||||
00:00:05:00:00:05,RebJean #1,plcfreshwater,False
|
||||
00:00:05:00:00:06,RobJane #1,plcfreshwater,False
|
||||
00:00:05:00:00:07,Kelsey #2,plcfreshwater,False
|
||||
00:00:05:00:00:09,Stephanie 41 #2,plcfreshwater,False
|
||||
00:00:05:00:00:10,Kelsey #1,plcfreshwater,False
|
||||
00:00:05:00:00:11,Stephanie 41 #3,plcfreshwater,False
|
||||
00:00:05:00:00:12,RobJane #4,plcfreshwater,False
|
||||
00:00:05:00:00:16,Terri #2,plcfreshwater,False
|
||||
00:00:05:00:00:15,Terri #1,plcfreshwater,False
|
||||
00:00:05:00:00:14,Terri #3,plcfreshwater,False
|
||||
00:00:05:00:00:13,Terri #4,plcfreshwater,False
|
||||
b8:27:eb:80:2e:f7,LimeQuest 5 WS 3-5,piflow,False
|
||||
00:00:05:00:00:18,Mary 43 #3,plcfreshwater,False
|
||||
00:00:05:00:00:19,Mary 43 #5,plcfreshwater,False
|
||||
00:00:05:00:00:20,Mary 43 #2,plcfreshwater,False
|
||||
00:00:05:00:00:21,Mary 43 #1,plcfreshwater,False
|
||||
00:00:05:00:00:22,KD #2,plcfreshwater,False
|
||||
00:00:05:00:00:23,KD #4,plcfreshwater,False
|
||||
00:00:05:00:00:24,KD #7,plcfreshwater,False
|
||||
00:00:05:00:00:25,KD #5,plcfreshwater,False
|
||||
00:00:02:00:00:01,Bobbie #1,plcfreshwater,False
|
||||
00:00:02:00:00:03,Bobbie #2,plcfreshwater,False
|
||||
00:00:02:00:00:04,Elizabeth A1,plcfreshwater,False
|
||||
00:00:02:00:00:05,Patty #1,plcfreshwater,False
|
||||
c4:93:00:0d:f2:80,Free Transfer Pit,transferlite,False
|
||||
00:00:02:00:00:06,Rhonda 2,plcfreshwater,False
|
||||
b8:27:eb:10:f5:1c,Wilkinson 34 WS 5-10,piflow,False
|
||||
b8:27:eb:c6:4d:a1,Wilkinson 33 WS 5-2,piflow,False
|
||||
b8:27:eb:fc:49:51,Wilkinson 33 WS 6-3,piflow,False
|
||||
b8:27:eb:1c:72:30,Wilkinson 37 WS 7-8,piflow,False
|
||||
b8:27:eb:ce:5d:4c,Wilkinson 33 WS 4-1,piflow,False
|
||||
b8:27:eb:b8:e9:52,Wilkinson 37 WS 8-8,piflow,False
|
||||
b8:27:eb:d8:b8:b6,Wilkinson 34 WS 1-8,piflow,False
|
||||
b8:27:eb:4f:f2:44,Wilkinson 39 WS 2-4,piflow,False
|
||||
00:00:00:00:00:25,Trumann 1,plcfreshwater,False
|
||||
00:00:00:00:00:26,Trumann 3,plcfreshwater,False
|
||||
00:00:00:00:00:27,Trumann 4,plcfreshwater,False
|
||||
00:00:00:00:00:28,Trumann 5,plcfreshwater,False
|
||||
00:00:00:00:00:29,Trumann 2,plcfreshwater,False
|
||||
00:00:02:00:00:07,Patty #2,plcfreshwater,False
|
||||
b8:27:eb:a6:a8:9a,Wilkinson 37 WS 10-9,piflow,False
|
||||
b8:27:eb:e4:44:da,Wilkinson 33 WS 3-1,piflow,False
|
||||
b8:27:eb:e0:0b:44,Wilkinson 34 WS 2-10,piflow,False
|
||||
b8:27:eb:8c:68:2a,Wilkinson 37 WS 1-5,piflow,False
|
||||
b8:27:eb:9b:fe:97,Wilkinson 37 WS 3-5,piflow,False
|
||||
b8:27:eb:0e:b3:e2,Wilkinson 37 WS 3-6,piflow,False
|
||||
b8:27:eb:d6:93:8b,Wilkinson 37 WS 5-7,piflow,False
|
||||
00:00:01:00:00:14,Kate A1,plcfreshwater,False
|
||||
00:00:01:00:00:15,Kate A2,plcfreshwater,False
|
||||
00:00:01:00:00:16,Kate B1,plcfreshwater,False
|
||||
00:00:01:00:00:17,Tessa Lyn,plcfreshwater,False
|
||||
00:00:02:00:00:10,Patty #3,plcfreshwater,False
|
||||
00:00:05:00:00:26,Smith #1,plcfreshwater,False
|
||||
00:00:05:00:00:27,Smith #2,plcfreshwater,False
|
||||
00:00:05:00:00:28,Dorcus,plcfreshwater,False
|
||||
00:00:06:00:00:01,Monique #1,plcfreshwater,False
|
||||
00:00:06:00:00:02,Monique #2,plcfreshwater,False
|
||||
00:00:06:00:00:03,Monique #3,plcfreshwater,False
|
||||
00:00:06:00:00:04,Dawn #2,plcfreshwater,False
|
||||
00:00:06:00:00:05,Dawn #3,plcfreshwater,False
|
||||
00:00:02:00:00:24,Yvonne Transfer Pump 3,plcfreshwater,False
|
||||
00:00:02:00:00:25,Yvonne Transfer Pump 2,plcfreshwater,False
|
||||
00:00:02:00:00:26,Yvonne Transfer Pump 1,plcfreshwater,False
|
||||
00:00:02:00:00:27,Bobbie #3,plcfreshwater,False
|
||||
00:00:05:00:00:29,Kelsey Pit,plcfreshwater,False
|
||||
b8:27:eb:83:24:8c,Wilkinson 34 WS 10-9,piflow,False
|
||||
c4:93:00:0d:f0:01,Banay WW 18 #5,flowmonitor,False
|
||||
b8:27:eb:e5:59:03,Wilkinson 39 WS 1-10,piflow,False
|
||||
b8:27:eb:c8:1c:07,Wilkinson 37 WS 4-7,piflow,False
|
||||
c4:93:00:0d:ef:fb,Banay WW 5-2,flowmonitor,False
|
||||
c4:93:00:0d:e8:69,Banay WW 8-3,flowmonitor,False
|
||||
c4:93:00:0d:ef:53,Banay WW 18 #7,flowmonitor,False
|
||||
c4:93:00:0d:f0:0d,Banay WW 806 North,flowmonitor,False
|
||||
c4:93:00:0d:e8:75,Banay WW 806 South,flowmonitor,False
|
||||
00:00:07:00:00:01,Banay WW 18 #8,plcfreshwater,False
|
||||
c4:93:00:0d:f3:73,Denali East Inlet,flowmonitor,False
|
||||
b8:27:eb:18:05:d6,Wilkinson 39 WS 2-8,piflow,False
|
||||
c4:93:00:0d:f1:36,Wilkinson Ranch 39 SR 1-1,advvfdipp,False
|
||||
c4:93:00:0d:e0:ef,Wilkinson 37 WS 1-7,advvfdipp,False
|
||||
b8:27:eb:62:ed:99,LimeQuest 5 WS 8-9,piflow,False
|
||||
b8:27:eb:ca:94:0f,LimeQuest 5 WS 1-4,piflow,False
|
||||
b8:27:eb:47:eb:ae,LimeQuest 10 WS 3-6,piflow,False
|
||||
c4:93:00:0b:0c:c9,Wrage 33 SR 3-3,advvfdipp,False
|
||||
c4:93:00:0d:f1:a8,N. Wilkinson Transfer Lite,transferlite,False
|
||||
b8:27:eb:c6:e5:b3,Wilkinson 33 WS 10-4,piflow,False
|
||||
b8:27:eb:a9:be:d4,Wilkinson 34 WS 9-9,piflow,False
|
||||
00:00:03:00:00:01,Lindsey #1,plcfreshwater,False
|
||||
00:00:03:00:00:02,Lindsey #2,plcfreshwater,False
|
||||
b8:27:eb:95:68:93,Wilkinson 1 WS 2-10,piflow,False
|
||||
b8:27:eb:56:42:2b,Wilkinson 33 WS 10-1A,piflow,False
|
||||
c4:93:00:0d:f2:89,Denali East Transfer Pump Monitor,dual_flowmeter,False
|
||||
c4:93:00:08:c6:81,Map Rock Transfer Pump Monitor #2,dual_flowmeter,False
|
||||
b8:27:eb:47:6b:9d,Wilkinson 37 WS 1-10,piflow,False
|
||||
b8:27:eb:51:cc:bc,Wilkinson 1 WS 1-10A,piflow,False
|
||||
b8:27:eb:eb:6a:81,Horton 34 WS 1-3,piflow,False
|
||||
b8:27:eb:19:83:ab,Wilkinson 39 WS 3-8,piflow,False
|
||||
b8:27:eb:5e:49:a6,Wilkinson 34 WS 6-10,piflow,False
|
||||
b8:27:eb:6e:7b:1b,Free 40 SR 2-1,piflow,False
|
||||
c4:93:00:08:d4:13,Nail Ranch 12 SR 1-3,advvfdipp,False
|
||||
b8:27:eb:5d:dd:09,Wilkinson 33 WS 6-2,piflow,False
|
||||
b8:27:eb:fd:a2:43,Wilkinson 39 WS 1-7,piflow,False
|
||||
b8:27:eb:d1:bc:61,Wilkinson 2 WS 2-9,piflow,False
|
||||
c4:93:00:0d:e9:41,Dawn Frac Pit,dual_flowmeter,False
|
||||
b8:27:eb:8a:a9:65,Wilkinson 34 WS 10-10,piflow,False
|
||||
b8:27:eb:a8:41:f0,Wilkinson 39 WS 2-10,piflow,False
|
||||
b8:27:eb:7c:d7:c5,Free 40 WS 1-1,piflow,False
|
||||
00:00:00:00:00:01,Barnett 19-2 WW,plcfreshwater,False
|
||||
00:00:00:00:00:31,Barnett 24-1,plcfreshwater,False
|
||||
b8:27:eb:42:c3:4c,Wilkinson 39 WS 1-6,piflow,False
|
||||
c4:93:00:08:cf:18,ToolBox North,advvfdipp,False
|
||||
b8:27:eb:50:ee:26,Wilkinson 33 WS 10-2,piflow,False
|
||||
c4:93:00:0b:0c:de,Nail Ranch 37 SR 3-2,advvfdipp,False
|
||||
b8:27:eb:28:f9:49,Wilkinson 37 WS 8-6,piflow,False
|
||||
00:00:02:00:00:28,Nancy Pit,plcfreshwater,False
|
||||
c4:93:00:0d:e9:53,Banay WW 18 #2,flowmonitor,False
|
||||
c4:93:00:0d:ef:26,Banay WW 18 #6,flowmonitor,False
|
||||
c4:93:00:0d:f1:c6,Banay WW 6-2,flowmonitor,False
|
||||
c4:93:00:0d:e9:3e,Banay WW #7,flowmonitor,False
|
||||
00:18:05:1e:ae:b8,Banay WW 7-2,plcfreshwater,False
|
||||
00:18:05:1f:8d:0b,Penny North,flowmonitor,False
|
||||
00:18:05:1f:8d:0e,Penny South,flowmonitor,False
|
||||
b8:27:eb:96:3c:23,Wilkinson 37 WS 5-5,piflow,False
|
||||
c4:93:00:06:71:aa,LLL 6 SR 1-1,advvfdipp,False
|
||||
b8:27:eb:48:aa:63,Wilkinson 39 WS 1-9,piflow,False
|
||||
b8:27:eb:40:0e:b2,Wilkinson 39 WS 1-8,piflow,False
|
||||
b8:27:eb:2d:86:50,Wilkinson 39 WS 2-6,piflow,False
|
||||
b8:27:eb:01:6c:fc,LimeQuest 5 WS 10-9,piflow,False
|
||||
b8:27:eb:28:e1:d6,Baylee Pit,dual_flowmeter,False
|
||||
00:00:06:00:00:06,Dawn to Terri,plcfreshwater,False
|
||||
c4:93:00:0e:e9:ee,Baylee Pit Transfer,dual_flowmeter,False
|
||||
00:00:05:00:00:31,TM1,plcfreshwater,False
|
||||
00:00:05:00:00:30,TM2,plcfreshwater,False
|
||||
00:00:05:00:00:32,WC41-1,plcfreshwater,False
|
||||
00:00:05:00:00:33,WC41-2,plcfreshwater,False
|
||||
00:00:05:00:00:34,WC41-3,plcfreshwater,False
|
||||
00:00:00:00:00:33,Jordan Pit Pump#1,plcfreshwater,False
|
||||
00:00:00:00:00:34,Jordan Pit Pump #2,plcfreshwater,False
|
||||
00:00:00:00:00:35,Jessica #6,plcfreshwater,False
|
||||
c4:93:00:0d:f2:41,Jones A,advvfdipp,False
|
||||
00:00:01:00:00:23,Kelly #1,plcfreshwater,False
|
||||
00:00:01:00:00:24,Kelly #2,plcfreshwater,False
|
||||
00:00:01:00:00:25,Kelly #3,plcfreshwater,False
|
||||
|
BIN
migration.xlsx
Normal file
BIN
migration.xlsx
Normal file
Binary file not shown.
@@ -476,7 +476,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "thingsboard",
|
||||
"display_name": "tbreport",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user