615 lines
34 KiB
INI
615 lines
34 KiB
INI
{
|
|
"controllers": [
|
|
{
|
|
"enable": 1,
|
|
"protocol": "Modbus-RTU",
|
|
"name": "flowmeter",
|
|
"args": {
|
|
"slaveAddr": 247,
|
|
"int16Ord": "ab",
|
|
"int32Ord": "abcd",
|
|
"float32Ord": "abcd",
|
|
"int64Ord": "abcdefgh",
|
|
"float64Ord": "abcdefgh",
|
|
"enableMsecSample": 0,
|
|
"continuousAcquisition": 1,
|
|
"maxContinuousNumber": 64,
|
|
"communicationInterval": 10,
|
|
"writeCoilFunction": 5,
|
|
"writeRegisterFunction": 6
|
|
},
|
|
"endpoint": "rs485",
|
|
"samplePeriod": 10,
|
|
"desc": "",
|
|
"expired": 1000,
|
|
"enableDebug": 0,
|
|
"enablePerOnchange": 0
|
|
},
|
|
{
|
|
"enable": 1,
|
|
"protocol": "Modbus-RTU",
|
|
"name": "drive",
|
|
"args": {
|
|
"slaveAddr": 1,
|
|
"int16Ord": "ab",
|
|
"int32Ord": "abcd",
|
|
"float32Ord": "abcd",
|
|
"int64Ord": "abcdefgh",
|
|
"float64Ord": "abcdefgh",
|
|
"enableMsecSample": 0,
|
|
"continuousAcquisition": 1,
|
|
"maxContinuousNumber": 64,
|
|
"communicationInterval": 100,
|
|
"writeCoilFunction": 5,
|
|
"writeRegisterFunction": 6
|
|
},
|
|
"endpoint": "rs485",
|
|
"samplePeriod": 10,
|
|
"desc": "",
|
|
"expired": 1000,
|
|
"enableDebug": 0,
|
|
"enablePerOnchange": 0
|
|
}
|
|
],
|
|
"measures": [
|
|
{
|
|
"name": "volume_flow",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "FLOAT",
|
|
"addr": "43874",
|
|
"decimal": 2,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_1",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "FLOAT",
|
|
"addr": "42610",
|
|
"decimal": 2,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_2",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "FLOAT",
|
|
"addr": "42810",
|
|
"decimal": 2,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_3",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "FLOAT",
|
|
"addr": "43010",
|
|
"decimal": 2,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "flow_unit",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "42103",
|
|
"enableBit": 0,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"deadZonePercent": "0",
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_1_units",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "44604",
|
|
"enableBit": 0,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"deadZonePercent": "0",
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_2_units",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "44605",
|
|
"enableBit": 0,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"deadZonePercent": "0",
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "totalizer_3_units",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "44606",
|
|
"enableBit": 0,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "reset_totalizers",
|
|
"ctrlName": "flowmeter",
|
|
"group": "",
|
|
"uploadType": "never",
|
|
"dataType": "INT",
|
|
"addr": "42609",
|
|
"enableBit": 0,
|
|
"readWrite": "rw",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "byte_order",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "onChange",
|
|
"dataType": "INT",
|
|
"addr": "44915",
|
|
"enableBit": 0,
|
|
"readWrite": "rw",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"deadZonePercent": "0",
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "device_name",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "onChange",
|
|
"dataType": "STRING",
|
|
"addr": "47238",
|
|
"len": 14,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "serial_number",
|
|
"ctrlName": "flowmeter",
|
|
"group": "default",
|
|
"uploadType": "onChange",
|
|
"dataType": "STRING",
|
|
"addr": "47003",
|
|
"len": 12,
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"storageLwTSDB": 0,
|
|
"transformType": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "frequency",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40785",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.01",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "current",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40784",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.1",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "pid_ref",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40792",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.1",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "pid_feedback",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40793",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.1",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "motor_rated_current",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "44897",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.1",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "sleep_delay",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "44925",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 2,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0,
|
|
"transDecimal": 2,
|
|
"gain": "0.1",
|
|
"offset": "0.0"
|
|
},
|
|
{
|
|
"name": "run_status",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40773",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 0,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "fault_a",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40816",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 0,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0
|
|
},
|
|
{
|
|
"name": "fault_b",
|
|
"ctrlName": "drive",
|
|
"group": "default",
|
|
"uploadType": "periodic",
|
|
"dataType": "INT",
|
|
"addr": "40817",
|
|
"readWrite": "ro",
|
|
"unit": "",
|
|
"desc": "",
|
|
"transformType": 0,
|
|
"storageLwTSDB": 0,
|
|
"enableBit": 0,
|
|
"msecSample": 0
|
|
}
|
|
],
|
|
"alarmLables": [
|
|
"default"
|
|
],
|
|
"alarms": [],
|
|
"groups": [
|
|
{
|
|
"name": "default",
|
|
"uploadInterval": 600,
|
|
"LwTSDBSize": 150000,
|
|
"strategy": 1,
|
|
"historyDataPath": "/var/user/data/dbhome/device_supervisor/LwTSDB",
|
|
"enablePerOnchange": 0
|
|
}
|
|
],
|
|
"misc": {
|
|
"maxAlarmRecordSz": 2000,
|
|
"logLvl": "INFO",
|
|
"coms": [
|
|
{
|
|
"name": "rs232",
|
|
"baud": 9600,
|
|
"bits": 8,
|
|
"stopbits": 1,
|
|
"parityChk": "n"
|
|
},
|
|
{
|
|
"name": "rs485",
|
|
"baud": 9600,
|
|
"bits": 8,
|
|
"stopbits": 1,
|
|
"parityChk": "n"
|
|
}
|
|
],
|
|
"cachePath": "/var/user/data/dbhome/device_supervisor/offlinedata",
|
|
"cacheSize": 10000,
|
|
"debugLogPath": "/var/user/data/dbhome/device_supervisor/debugLog",
|
|
"debugLogSize": 2000
|
|
},
|
|
"clouds": [
|
|
{
|
|
"cacheSize": 10000,
|
|
"enable": 1,
|
|
"name": "default",
|
|
"type": "Standard MQTT",
|
|
"args": {
|
|
"host": "hp.henrypump.cloud",
|
|
"port": 1883,
|
|
"clientId": "wilkinson-39-ws-1-6",
|
|
"auth": 1,
|
|
"tls": 0,
|
|
"cleanSession": 0,
|
|
"mqttVersion": "v3.1.1",
|
|
"keepalive": 60,
|
|
"key": "",
|
|
"cert": "",
|
|
"rootCA": "",
|
|
"verifyServer": 0,
|
|
"verifyClient": 0,
|
|
"username": "3g2a34mp06lel703qism",
|
|
"passwd": "",
|
|
"willQos": 0,
|
|
"willRetain": 0,
|
|
"willTopic": "",
|
|
"willPayload": "",
|
|
"tlsAuth": "caSelfSigned"
|
|
},
|
|
"uploadRules": []
|
|
}
|
|
],
|
|
"quickfaas": {
|
|
"genericFuncs": [],
|
|
"uploadFuncs": [
|
|
{
|
|
"qos": 1,
|
|
"funcName": "sendData",
|
|
"script": "# Enter your python code.\nimport json, os, time, shutil\nfrom datetime import datetime as dt\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\nfrom quickfaas.global_dict import get as get_params\nfrom quickfaas.global_dict import _set_global_args\nfrom mobiuspi_lib.gps import GPS\n\npayload = {}\n\ndef initialize_totalizers():\n return {\n \"totalizer_1_day\": 0,\n \"totalizer_1_week\": 0,\n \"totalizer_1_month\": 0,\n \"totalizer_1_year\": 0,\n \"totalizer_1_lifetime\": 0,\n \"totalizer_1_dayHolding\": 0,\n \"totalizer_1_weekHolding\": 0,\n \"totalizer_1_monthHolding\": 0,\n \"totalizer_1_yearHolding\": 0,\n \"totalizer_1_rolloverCounter\": 0,\n \"totalizer_2_day\": 0,\n \"totalizer_2_week\": 0,\n \"totalizer_2_month\": 0,\n \"totalizer_2_year\": 0,\n \"totalizer_2_lifetime\": 0,\n \"totalizer_2_dayHolding\": 0,\n \"totalizer_2_weekHolding\": 0,\n \"totalizer_2_monthHolding\": 0,\n \"totalizer_2_yearHolding\": 0,\n \"totalizer_2_rolloverCounter\": 0,\n \"totalizer_3_day\": 0,\n \"totalizer_3_week\": 0,\n \"totalizer_3_month\": 0,\n \"totalizer_3_year\": 0,\n \"totalizer_3_lifetime\": 0,\n \"totalizer_3_dayHolding\": 0,\n \"totalizer_3_weekHolding\": 0,\n \"totalizer_3_monthHolding\": 0,\n \"totalizer_3_yearHolding\": 0,\n \"totalizer_3_rolloverCounter\": 0\n }\n\ndef getTotalizers(file_path=\"/var/user/files/totalizers.json\"):\n \"\"\"\n Retrieves totalizer data from a JSON file.\n\n :param file_path: Path to the JSON file storing totalizer data.\n :return: Dictionary containing totalizer values.\n \"\"\"\n try:\n with open(file_path, \"r\") as t:\n totalizers = json.load(t)\n if not totalizers or not isinstance(totalizers, dict):\n logger.info(\"Invalid data format in the file. Initializing totalizers.\")\n totalizers = initialize_totalizers()\n except FileNotFoundError:\n logger.info(\"File not found. Initializing totalizers.\")\n totalizers = initialize_totalizers()\n except json.JSONDecodeError:\n timestamp = dt.now().strftime(\"%Y%m%d_%H%M%S\")\n # Split the file path and insert the timestamp before the extension\n file_name, file_extension = os.path.splitext(file_path)\n backup_file_path = f\"{file_name}_{timestamp}{file_extension}\"\n shutil.copyfile(file_path, backup_file_path)\n logger.error(f\"Error decoding JSON. A backup of the file is created at {backup_file_path}. Initializing totalizers.\")\n totalizers = initialize_totalizers()\n return totalizers\n\n\ndef chunk_payload(payload, chunk_size=20):\n if \"values\" in payload:\n # Original format: {\"ts\": ..., \"values\": {...}}\n chunked_values = list(payload[\"values\"].items())\n for i in range(0, len(chunked_values), chunk_size):\n yield {\n \"ts\": payload[\"ts\"],\n \"values\": dict(chunked_values[i:i+chunk_size])\n }\n else:\n # New format: {\"key1\": \"value1\", \"key2\": \"value2\"}\n chunked_keys = list(payload.keys())\n for i in range(0, len(chunked_keys), chunk_size):\n yield {k: payload[k] for k in chunked_keys[i:i+chunk_size]}\n\ndef sendData(message):\n logger.debug(message)\n payload = {\"ts\": (round(dt.timestamp(dt.now())/600)*600)*1000, \"values\": {}}\n resetPayload = {\"ts\": \"\", \"values\": {}}\n dayReset, weekReset, monthReset, yearReset = False, False, False, False\n for measure in message['measures']:\n try:\n if measure[\"health\"] == 1:\n if measure[\"name\"] in [\"totalizer_1\", \"totalizer_2\", \"totalizer_3\"]:\n payload[\"values\"][\"year_\" + measure[\"name\"]], yearReset = totalizeYear(measure[\"value\"], measure[\"name\"])\n payload[\"values\"][\"month_\" + measure[\"name\"]], monthReset = totalizeMonth(measure[\"value\"], measure[\"name\"])\n payload[\"values\"][\"week_\" + measure[\"name\"]], weekReset = totalizeWeek(measure[\"value\"], measure[\"name\"])\n payload[\"values\"][\"today_\" + measure[\"name\"]], dayReset = totalizeDay(measure[\"value\"], measure[\"name\"])\n elif measure[\"name\"] in [\"totalizer_1_units\", \"totalizer_2_units\", \"totalizer_3_units\", \"flow_unit\"]:\n payload[\"values\"][measure[\"name\"]] = convert_int(measure[\"name\"], measure[\"value\"])\n elif measure[\"name\"] in [\"run_status\"]:\n payload[\"values\"][measure[\"name\"]] = status_codes(measure[\"value\"])\n elif measure[\"name\"] in [ \"fault_a\"]:\n payload[\"values\"][measure[\"name\"]] = fault_code_a(measure[\"value\"])\n elif measure[\"name\"] in [\"fault_b\"]:\n payload[\"values\"][measure[\"name\"]] = fault_code_b(measure[\"value\"])\n else:\n payload[\"values\"][measure[\"name\"]] = measure[\"value\"]\n except Exception as e:\n logger.error(e)\n \n for chunk in chunk_payload(payload=payload):\n publish(__topic__, json.dumps(chunk), __qos__)\n time.sleep(2)\n try:\n publish(\"v1/devices/me/attributes\", json.dumps({\"latestReportTime\": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)\n except Exception as e:\n logger.error(e)\n \n if dayReset:\n resetPayload[\"values\"][\"yesterday_totalizer_1\"] = payload[\"values\"][\"today_totalizer_1\"]\n resetPayload[\"values\"][\"yesterday_totalizer_2\"] = payload[\"values\"][\"today_totalizer_2\"]\n resetPayload[\"values\"][\"yesterday_totalizer_3\"] = payload[\"values\"][\"today_totalizer_3\"]\n resetPayload[\"values\"][\"today_totalizer_1\"] = 0\n resetPayload[\"values\"][\"today_totalizer_2\"] = 0\n resetPayload[\"values\"][\"today_totalizer_3\"] = 0\n if weekReset:\n resetPayload[\"values\"][\"last_week_totalizer_1\"] = payload[\"values\"][\"week_totalizer_1\"]\n resetPayload[\"values\"][\"last_week_totalizer_2\"] = payload[\"values\"][\"week_totalizer_1\"]\n resetPayload[\"values\"][\"last_week_totalizer_3\"] = payload[\"values\"][\"week_totalizer_3\"]\n resetPayload[\"values\"][\"week_totalizer_1\"] = 0\n resetPayload[\"values\"][\"week_totalizer_2\"] = 0\n resetPayload[\"values\"][\"week_totalizer_3\"] = 0\n if monthReset:\n resetPayload[\"values\"][\"last_month_totalizer_1\"] = payload[\"values\"][\"month_totalizer_1\"]\n resetPayload[\"values\"][\"last_month_totalizer_2\"] = payload[\"values\"][\"month_totalizer_2\"]\n resetPayload[\"values\"][\"last_month_totalizer_3\"] = payload[\"values\"][\"month_totalizer_3\"]\n resetPayload[\"values\"][\"month_totalizer_1\"] = 0\n resetPayload[\"values\"][\"month_totalizer_2\"] = 0\n resetPayload[\"values\"][\"month_totalizer_3\"] = 0\n if yearReset:\n resetPayload[\"values\"][\"last_year_totalizer_1\"] = payload[\"values\"][\"year_totalizer_1\"]\n resetPayload[\"values\"][\"last_year_totalizer_2\"] = payload[\"values\"][\"year_totalizer_2\"]\n resetPayload[\"values\"][\"last_year_totalizer_3\"] = payload[\"values\"][\"year_totalizer_3\"]\n resetPayload[\"values\"][\"year_totalizer_1\"] = 0 \n resetPayload[\"values\"][\"year_totalizer_2\"] = 0 \n resetPayload[\"values\"][\"year_totalizer_3\"] = 0 \n\n if resetPayload[\"values\"]:\n resetPayload[\"ts\"] = 1 + (round(dt.timestamp(dt.now())/600)*600)*1000\n publish(__topic__, json.dumps(resetPayload), __qos__) \n\ndef saveTotalizers(totalizers, file_path=\"/var/user/files/totalizers.json\"):\n \"\"\"\n Saves totalizer data to a JSON file.\n\n :param totalizers: Dictionary containing totalizer values to be saved.\n :param file_path: Path to the JSON file where totalizer data will be saved.\n \"\"\"\n try:\n with open(file_path, \"w\") as t:\n json.dump(totalizers, t)\n except (IOError, OSError, json.JSONEncodeError) as e:\n logger.error(f\"Error saving totalizers to {file_path}: {e}\")\n raise # Optionally re-raise the exception if it should be handled by the caller\n\ndef totalizeDay(lifetime, totalizer, max_retries=3, retry_delay=2):\n \"\"\"\n Update and save daily totalizers based on the lifetime value.\n\n :param lifetime: The current lifetime total.\n :param max_retries: Maximum number of save attempts.\n :param retry_delay: Delay in seconds between retries.\n :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails.\n \"\"\"\n totalizers = getTotalizers()\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n reset = False\n value = (lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000) - totalizers[totalizer + \"_dayHolding\"]\n\n if not int(now.strftime(\"%d\")) == int(totalizers[totalizer + \"_day\"]):\n totalizers[totalizer + \"_dayHolding\"] = lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000\n totalizers[totalizer + \"_day\"] = int(now.strftime(\"%d\"))\n\n for attempt in range(max_retries):\n try:\n saveTotalizers(totalizers)\n reset = True\n return (value, reset)\n except Exception as e:\n logger.error(f\"Attempt {attempt + 1} failed to save totalizers: {e}\")\n if attempt < max_retries - 1:\n time.sleep(retry_delay)\n else:\n logger.error(\"All attempts to save totalizers failed.\")\n return (None, False)\n return (value, reset)\n\ndef totalizeWeek(lifetime, totalizer, max_retries=3, retry_delay=2):\n \"\"\"\n Update and save weekly totalizers based on the lifetime value.\n\n :param lifetime: The current lifetime total.\n :param max_retries: Maximum number of save attempts.\n :param retry_delay: Delay in seconds between retries.\n :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails.\n \"\"\"\n totalizers = getTotalizers()\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n reset = False\n value = (lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000) - totalizers[totalizer + \"_weekHolding\"]\n if (not now.strftime(\"%U\") == totalizers[totalizer + \"_week\"] and now.strftime(\"%a\") == \"Sun\") or totalizers[totalizer + \"_week\"] == 0:\n totalizers[totalizer + \"_weekHolding\"] = lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000\n totalizers[totalizer + \"_week\"] = now.strftime(\"%U\")\n\n for attempt in range(max_retries):\n try:\n saveTotalizers(totalizers)\n reset = True\n return (value, reset)\n except Exception as e:\n logger.error(f\"Attempt {attempt + 1} failed to save totalizers: {e}\")\n if attempt < max_retries - 1:\n time.sleep(retry_delay)\n else:\n logger.error(\"All attempts to save totalizers failed.\")\n return (None, False)\n return (value, reset)\n\ndef totalizeMonth(lifetime, totalizer, max_retries=3, retry_delay=2):\n \"\"\"\n Update and save monthly totalizers based on the lifetime value.\n\n :param lifetime: The current lifetime total.\n :param max_retries: Maximum number of save attempts.\n :param retry_delay: Delay in seconds between retries.\n :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails.\n \"\"\"\n totalizers = getTotalizers()\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n reset = False\n value = (lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000) - totalizers[totalizer + \"_monthHolding\"]\n if not int(now.strftime(\"%m\")) == int(totalizers[totalizer + \"_month\"]):\n totalizers[totalizer + \"_monthHolding\"] = lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000\n totalizers[totalizer + \"_month\"] = now.strftime(\"%m\")\n\n for attempt in range(max_retries):\n try:\n saveTotalizers(totalizers)\n reset = True\n return (value, reset)\n except Exception as e:\n logger.error(f\"Attempt {attempt + 1} failed to save totalizers: {e}\")\n if attempt < max_retries - 1:\n time.sleep(retry_delay)\n else:\n logger.error(\"All attempts to save totalizers failed.\")\n return (None, False)\n\n return (value,reset)\n\ndef totalizeYear(lifetime, totalizer, max_retries=3, retry_delay=2):\n \"\"\"\n Update and save yearly totalizers based on the lifetime value.\n\n :param lifetime: The current lifetime total.\n :param max_retries: Maximum number of save attempts.\n :param retry_delay: Delay in seconds between retries.\n :return: A tuple containing the calculated value and a boolean indicating if a reset occurred, or (None, False) if save fails.\n \"\"\"\n totalizers = getTotalizers()\n if not totalizers.get(\"rolloverCounter\"):\n totalizers[totalizer + \"_rolloverCounter\"] = 0\n totalizers[totalizer + \"_lastRawLifetime\"] = lifetime\n now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)\n reset = False\n if totalizers[totalizer + \"_lastRawLifetime\"] > lifetime:\n totalizers[totalizer + \"_rolloverCounter\"] += 1\n totalizers[totalizer + \"_lastRawLifetime\"] = lifetime\n\n value = (lifetime + totalizers[totalizer + \"_rolloverCounter\"] * 10000000) - totalizers[totalizer + \"_yearHolding\"]\n if not int(now.strftime(\"%Y\")) == int(totalizers[totalizer + \"_year\"]):\n totalizers[totalizer + \"_yearHolding\"] = lifetime\n totalizers[totalizer + \"_year\"] = now.strftime(\"%Y\")\n totalizers[totalizer + \"_rolloverCounter\"] = 0\n\n for attempt in range(max_retries):\n try:\n saveTotalizers(totalizers)\n reset = True\n return (value, reset)\n except Exception as e:\n logger.error(f\"Attempt {attempt + 1} failed to save totalizers: {e}\")\n if attempt < max_retries - 1:\n time.sleep(retry_delay)\n else:\n logger.error(\"All attempts to save totalizers failed.\")\n return (None, False)\n\n\ndef int_to_bits(n,x):\n return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the \"0b\" part\n\ndef pad_to_x(n,x):\n while len(n) < x:\n n = [0] + n\n return n\n\ndef status_codes(n):\n\n status_array = int_to_bits(n,16)\n status_low = {\n 0: \"Stopped;\",\n 1: \"Operating in Forward;\",\n 2: \"Operating in Reverse;\",\n 3: \"DC operating;\"\n }\n status_mid = {\n 0: \"\",\n 1: \"Speed searching;\",\n 2: \"Accelerating;\",\n 3: \"At constant speed;\",\n 4: \"Decelerating;\",\n 5: \"Decelerating to stop;\",\n 6: \"H/W OCS;\",\n 7: \"S/W OCS;\",\n 8: \"Dwell operating;\"\n }\n status_high = {\n 0: \"Normal state\",\n 4: \"Warning occurred\",\n 8: \"Fault occurred\"\n }\n values = {\n 0: 8,\n 1: 4,\n 2: 2,\n 3: 1\n }\n\n stats_low = status_array[12:]\n stats_mid = status_array[8:12]\n stats_high = status_array[:4]\n low = 0\n mid = 0\n high = 0\n for x in range(4):\n if stats_low[x] == 1:\n low = low + values[x]\n if stats_mid[x] == 1:\n mid = mid + values[x]\n if stats_high[x] == 1:\n high = high + values[x]\n\n return status_low[low] + \" \" + status_mid[mid] + ' ' + status_high[high] \n\ndef fault_code_a(n):\n\n fault_code_array = int_to_bits(n,16)\n\n \"\"\" fault = {\n 0: \"OCT\",\n 1: \"OVT\",\n 2: \"EXT-A\",\n 3: \"EST\",\n 4: \"COL\",\n 5: \"GFT\",\n 6: \"OHT\",\n 7: \"ETH\",\n 8: \"OLT\",\n 9: \"Reserved\",\n 10: \"EXT-B\",\n 11: \"EEP\",\n 12: \"FAN\",\n 13: \"POT\",\n 14: \"IOLT\",\n 15: \"LVT\"\n } \"\"\"\n fault = {\n 0: \"Overload Trip\",\n 1: \"Underload Trip\",\n 2: \"Inverter Overload Trip\",\n 3: \"E-Thermal Trip\",\n 4: \"Ground Fault Trip\",\n 5: \"Output Image Trip\",\n 6: \"Inmput Imaging Trip\",\n 7: \"Reserved\",\n 8: \"Reserved\",\n 9: \"NTC Trip\",\n 10: \"Overcurrent Trip\",\n 11: \"Overvoltage Trip\",\n 12: \"External Trip\",\n 13: \"Arm Short\",\n 14: \"Over Heat Trip\",\n 15: \"Fuse Open Trip\"\n }\n\n faults = []\n counter = 15\n for x in range(16):\n if fault_code_array[x] == 1:\n faults = [fault[counter]] + faults\n counter = counter - 1\n return ' '.join(faults)\n\ndef fault_code_b(n):\n\n fault_code_array = int_to_bits(n,8)\n\n \"\"\" fault = {\n 0: \"COM\",\n 1: \"Reserved\",\n 2: \"NTC\",\n 3: \"REEP\",\n 4: \"OC2\",\n 5: \"NBR\",\n 6: \"SAFA\",\n 7: \"SAFB\"\n } \"\"\"\n fault = {\n 0: \"Reserved\",\n 1: \"Reserved\",\n 2: \"Reserved\",\n 3: \"FAN Trip\",\n 4: \"Reserved\",\n 5: \"Reserved\",\n 6: \"Pre PID Fail\",\n 7: \"Bad contact at basic I/O board\",\n 8: \"External Brake Trip\",\n 9: \"No Motor Trip\",\n 10: \"Bad Option Card\",\n 11: \"Reserved\",\n 12: \"Reserved\",\n 13: \"Reserved\",\n 14: \"Pre Over Heat Trip\",\n 15: \"Reserved\"\n }\n\n faults = []\n counter = 7\n for x in range(8):\n if fault_code_array[x] == 1:\n faults = [fault[counter]] + faults\n counter = counter - 1\n return ' '.join(faults)\n\n\n\ndef convert_int(measure, value):\n \n totalizer_codes = {\n 0: \"cm cubed\", \n 1: \"dm cubed\",\n 2: \"m cubed\", \n 3: \"ml\", \n 4: \"l\", \n 5: \"hl\", \n 6: \"Ml Mega\",\n 8: \"af\", \n 9: \"ft cubed\", \n 10: \"fl oz (us)\", \n 11: \"gal (us)\", \n 12: \"Mgal (us)\", \n 13: \"bbl (us;liq.)\", \n 14: \"bbl (us;beer)\", \n 15: \"bbl (us;oil)\", \n 16: \"bbl (us;tank)\", \n 17: \"gal (imp)\",\n 18: \"Mgal (imp)\", \n 19: \"bbl (imp;beer)\", \n 20: \"bbl (imp;oil)\", \n 22: \"kgal (us)\",\n 23: \"Mft cubed\",\n 50: \"g\",\n 51: \"kg\", \n 52: \"t\",\n 53: \"oz\", \n 54: \"lb\", \n 55: \"STon\", \n 100: \"Nl\", \n 101: \"Nm cubed\", \n 102: \"Sm cubed\", \n 103: \"Sft cubed\", \n 104: \"Sl\", \n 105: \"Sgal (us)\", \n 106: \"Sbbl (us;liq.)\", \n 107: \"Sgal (imp)\",\n 108: \"Sbbl (us;oil)\", \n 109: \"MMSft cubed\", \n 110: \"Nhl\",\n 251: \"None\" \n }\n\n flow_codes = {\n 0: \"cm cubed/s\",\n 1: \"cm cubed/min\",\n 2: \"cm cubed/h\",\n 3: \"cm cubed/d\",\n 4: \"dm cubed/s\",\n 5: \"dm cubed/min\",\n 6: \"dm cubed/h\",\n 7: \"dm cubed/d\",\n 8: \"m cubed/s\",\n 9: \"m cubed/min\",\n 10: \"m cubed/h\",\n 11: \"m cubed/d\",\n 12: \"ml/s\",\n 13: \"ml/min\",\n 14: \"ml/h\",\n 15: \"ml/d\",\n 16: \"l/s\",\n 17: \"l/min\",\n 18: \"l/h (+)\",\n 19: \"l/d\",\n 20: \"hl/s\",\n 21: \"hl/min\",\n 22: \"hl/h\",\n 23: \"hl/d\",\n 24: \"Ml/s\",\n 25: \"Ml/min\",\n 26: \"Ml/h\",\n 27: \"Ml/d\",\n 32: \"af/s\",\n 33: \"af/min\",\n 34: \"af/h\",\n 35: \"af/d\",\n 36: \"ft cubed/s\",\n 37: \"ft cubed/min\",\n 38: \"ft cubed/h\",\n 39: \"ft cubed/d\",\n 40: \"fl oz/s (us)\",\n 41: \"fl oz/min (us)\",\n 42: \"fl oz/h (us)\",\n 43: \"fl oz/d (us)\",\n 44: \"gal/s (us)\",\n 45: \"gal/min (us)\",\n 46: \"gal/h (us)\",\n 47: \"gal/d (us)\",\n 48: \"Mgal/s (us)\",\n 49: \"Mgal/min (us)\",\n 50: \"Mgal/h (us)\",\n 51: \"Mgal/d (us)\",\n 52: \"bbl/s (us;liq.)\",\n 53: \"bbl/min (us;liq.)\",\n 54: \"bbl/h (us;liq.)\",\n 55: \"bbl/d (us;liq.)\",\n 56: \"bbl/s (us;beer)\",\n 57: \"bbl/min (us;beer)\",\n 58: \"bbl/h (us;beer)\",\n 59: \"bbl/d (us;beer)\",\n 60: \"bbl/s (us;oil)\",\n 61: \"bbl/min (us;oil)\",\n 62: \"bbl/h (us;oil)\",\n 63: \"bbl/d (us;oil)\",\n 64: \"bbl/s (us;tank)\",\n 65: \"bbl/min (us;tank)\",\n 66: \"bbl/h (us;tank)\",\n 67: \"bbl/d (us;tank)\",\n 68: \"gal/s (imp)\",\n 69: \"gal/min (imp)\",\n 70: \"gal/h (imp)\",\n 71: \"gal/d (imp)\",\n 72: \"Mgal/s (imp)\",\n 73: \"Mgal/min (imp)\",\n 74: \"Mgal/h (imp)\",\n 75: \"Mgal/d (imp)\",\n 76: \"bbl/s (imp;beer)\",\n 77: \"bbl/min (imp;beer)\",\n 78: \"bbl/h (imp;beer)\",\n 79: \"bbl/d (imp;beer)\",\n 80: \"bbl/s (imp;oil)\",\n 81: \"bbl/min (imp;oil)\",\n 82: \"bbl/h (imp;oil)\",\n 83: \"bbl/d (imp;oil)\",\n 88: \"kgal/s (us)\",\n 89: \"kgal/min (us)\",\n 90: \"kgal/h (us)\",\n 91: \"kgal/d (us)\",\n 92: \"MMft cubed/s\",\n 93: \"MMft cubed/min\",\n 94: \"MMft cubed/h\",\n 96: \"Mft cubed/d\"\n }\n\n \n\n piflow = {\n \"totalizer_1_units\": totalizer_codes.get(value, \"Invalid Code\"),\n \"totalizer_2_units\": totalizer_codes.get(value, \"Invalid Code\"),\n \"totalizer_3_units\": totalizer_codes.get(value, \"Invalid Code\"),\n \"flow_unit\": flow_codes.get(value, \"Invalid Code\"),\n }\n\n return piflow.get(measure, \"Invalid Tag\")\n",
|
|
"name": "sendData",
|
|
"trigger": "measure_event",
|
|
"topic": "v1/devices/me/telemetry",
|
|
"cloudName": "default",
|
|
"groups": [
|
|
"default"
|
|
],
|
|
"msgType": 0
|
|
}
|
|
],
|
|
"downloadFuncs": []
|
|
},
|
|
"labels": [
|
|
{
|
|
"key": "SN",
|
|
"value": "GF5022311031799"
|
|
},
|
|
{
|
|
"key": "MAC",
|
|
"value": "00:18:05:28:4a:37"
|
|
}
|
|
],
|
|
"modbusSlave": {
|
|
"enable": 0,
|
|
"protocol": "Modbus-TCP",
|
|
"port": 502,
|
|
"slaveAddr": 1,
|
|
"int16Ord": "ab",
|
|
"int32Ord": "abcd",
|
|
"float32Ord": "abcd",
|
|
"maxConnection": 5,
|
|
"mapping_table": []
|
|
},
|
|
"modbusRTUSlave": {
|
|
"enable": 0,
|
|
"protocol": "Modbus-RTU",
|
|
"coms": "rs485",
|
|
"slaveAddr": 1,
|
|
"int16Ord": "ab",
|
|
"int32Ord": "abcd",
|
|
"float32Ord": "abcd",
|
|
"mapping_table": []
|
|
},
|
|
"iec104Server": {
|
|
"enable": 0,
|
|
"cotSize": 2,
|
|
"port": 2404,
|
|
"serverList": [
|
|
{
|
|
"asduAddr": 1
|
|
}
|
|
],
|
|
"kValue": 12,
|
|
"wValue": 8,
|
|
"t0": 30,
|
|
"t1": 15,
|
|
"t2": 10,
|
|
"t3": 20,
|
|
"maximumLink": 5,
|
|
"timeSet": 1,
|
|
"byteOrder": "abcd",
|
|
"mapping_table": []
|
|
},
|
|
"iec101Server": {
|
|
"enable": 0,
|
|
"coms": "rs485",
|
|
"mode": "UnBalance",
|
|
"linkLen": 2,
|
|
"linkAddr": 1,
|
|
"asduLen": 2,
|
|
"ioaLen": 3,
|
|
"cotLen": 2,
|
|
"serverList": [
|
|
{
|
|
"asduAddr": 1
|
|
}
|
|
],
|
|
"linkTimeOut": 2000,
|
|
"timeSet": 1,
|
|
"idleTimeOut": 10000,
|
|
"byteOrder": "abcd",
|
|
"mapping_table": {
|
|
"YX": [],
|
|
"YC": [],
|
|
"YK": []
|
|
}
|
|
},
|
|
"iec104Client": {
|
|
"enable": 0,
|
|
"connectType": 2,
|
|
"serverAddr": "ipower.inhandcloud.cn",
|
|
"serverPort": 2406,
|
|
"communicationCode": "",
|
|
"protocol": 1,
|
|
"asduAddr": 1,
|
|
"tls": 1,
|
|
"verification": 1,
|
|
"mapping_table": {
|
|
"YX": [],
|
|
"YC": [],
|
|
"YK": []
|
|
}
|
|
},
|
|
"opcuaServer": {
|
|
"enable": 0,
|
|
"port": 4840,
|
|
"maximumLink": 5,
|
|
"securityMode": 0,
|
|
"identifierType": "String",
|
|
"pubsub": 0,
|
|
"certificate": "None",
|
|
"privateKey": "None",
|
|
"mapping_table": []
|
|
},
|
|
"sl651Slave": {
|
|
"enable": 0,
|
|
"centerAaddr": 1,
|
|
"remoteAddr": "",
|
|
"addrCode": "",
|
|
"password": "",
|
|
"platform_list": [],
|
|
"mapping_table": []
|
|
},
|
|
"hj212Client": {
|
|
"enable": 0,
|
|
"platform_list": [],
|
|
"block_list": [],
|
|
"mapping_table": []
|
|
},
|
|
"southMetadata": {},
|
|
"bindMetadata": {},
|
|
"bindConfig": {
|
|
"enable": 0,
|
|
"bind": {
|
|
"modelId": "",
|
|
"modelName": "",
|
|
"srcId": "",
|
|
"srcName": "",
|
|
"devId": "",
|
|
"devName": ""
|
|
},
|
|
"varGroups": [],
|
|
"variables": [],
|
|
"alerts": []
|
|
},
|
|
"templates": {},
|
|
"version": "2.7.1"
|
|
} |