diff --git a/config b/config
index b10cd71..4b75027 100644
--- a/config
+++ b/config
@@ -6,7 +6,8 @@ package#flow (Object) : { url: '/' }
table.relays : line:number|tbname:string|contactor:number|profile:string
-table.nodes : node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean
-table.settings : rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
+table.nodes : node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean|time_of_last_communication:number
+table.settings : rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number
table.pins : pin:string|type:string|line:number
table.notifications : key:string|weight:string|sk:string|en:string
+table.status : thermometer:string|em:string|twilight_sensor:string
diff --git a/databases/modbus_config.js b/databases/modbus_config.js
deleted file mode 100644
index b73116a..0000000
--- a/databases/modbus_config.js
+++ /dev/null
@@ -1,114 +0,0 @@
-const timeoutInterval = 150000;
-
-const deviceConfig = [
- {
- device: "em340",
- deviceAddress: 1,
- stream: [
- {
- "tbAttribute": "Phase_1_voltage",
- "register": 0,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_2_voltage",
- "register": 2,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_3_voltage",
- "register": 4,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_1_current",
- "register": 12,
- "size": 2,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "Phase_2_current",
- "register": 14,
- "size": 2,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "Phase_3_current",
- "register": 16,
- "size": 2,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "Phase_1_power",
- "register": 18,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_2_power",
- "register": 20,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_3_power",
- "register": 22,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "total_power",
- "register": 40,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "total_energy",
- "register": 52,
- "size": 2,
- "multiplier": 0.1
- },
- {
- "tbAttribute": "Phase_1_pow_factor",
- "register": 46,
- "size": 1,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "Phase_2_pow_factor",
- "register": 47,
- "size": 1,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "Phase_3_pow_factor",
- "register": 48,
- "size": 1,
- "multiplier": 0.001
- },
- {
- "tbAttribute": "power_factor",
- "register": 49,
- "size": 1,
- "multiplier": 0.001
- }
- ]
- },
- {
- device: "twilight_sensor",
- deviceAddress: 2,
- stream: [
- {
- "tbAttribute": "twilight_sensor",
- "register": 60,
- "size": 2,
- "multiplier": 1
- }
- ]
- }
-];
-
-module.exports = { timeoutInterval, deviceConfig };
\ No newline at end of file
diff --git a/databases/nodes.table b/databases/nodes.table
index 57331db..e3f5e54 100644
--- a/databases/nodes.table
+++ b/databases/nodes.table
@@ -1,31 +1,8 @@
-node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean
-+|3522|RO8rjaBDy21qPQJzW7oD96ApK3xmNleVZg9Ed4Gw|1||1|1|...........
-+|4018|3JjOWdylwgNLzxVab7NEznkZ2vG64rq8PEB5QmDo|1||1|1|...........
-+|4019|Z5KyJe9nEg1QNbWlX0wWRB0oDjBLdqzR83VGv624|1||1|1|...........
-+|4154|1JMYvnx2RzKEo4aWQ7DmN5AL8yZV3m9NBePXbrdj|1||1|0|...........
-+|3907|PjLblDgRBO6WQqnxmkJ59r0Jv3ewZN4p5a89yKdY|1||1|1|...........
-+|4148|dz4ojlpP85JMgDLZWkQOoGAaKYqQexEr62GXRV1y|1||1|1|...........
-+|4153|d5xjWYMwEJon6rLlK7yBYmAqgV4DaOeNB9ZX3Gzb|1||1|1|...........
-+|3938|gRoJEyXVx4qD9er287LP1v7wBzGldaPjLWQKm3Mv|1||1|1|...........
-+|3802|K94XLav1glVRnyQ6r01BNzkme3YJwBxM5oOzdP2j|1||1|1|...........
-+|4015|d9x2V5LGYBzXp4mMRAOBDj7PloaqJwnQj6DgrNe3|1||1|0|...........
-+|3929|B5EoxeMVp4zwr8nqW0GjDpARjvD1PNamOGbLg63Z|1||1|1|...........
-+|3946|aw4eELG2DlPMdn1JW0B1DnAqQXOZRN3xB5yp8VKr|1||1|1|...........
-+|4014|ZmRwd93QL4gaezxEbAxW5971prn2XjlPvGyqJ6BO|1||1|1|...........
-+|4155|eod9aRWLVl34Gx1Dn7VoaaA2rz6qjgmpEXwQJN5Z|1||1|1|...........
-+|4149|3a5oqJN1bgnx4Ol9dk86NBAByE6jQ8mKDWMpGrLV|1||1|1|...........
-+|3642|EjgWGnXaLy9opPOz20n694086BlYM3w1deVQvbKr|1||1|1|...........
-+|3636|wvKJdZML6mXP4DzWBAXWNW7jxNloa5g23Ve9Y1ry|1||1|1|...........
-+|3991|Nzp2OoJlqn6r1ZgvdA3GWdAabBwP5G4eE3RQmyxD|1||1|1|...........
-+|3994|PLBJzmK1r3Gynd6OW0gGdM0e5wV4vx9bDEqNgYR8|1||1|1|...........
-+|3990|52dD6ZlV1QaOpRBmbAqKZgkKnGzWMLj4eJq38Pgo|1||1|1|...........
-+|3967|rDbQ84xzwgdqEoPm3kbJw3k9anOZY1RXyBv2LVM6|1||1|1|...........
-+|3977|E6Kg9oDnLWyzPRMva7vrwa7Jxp4VG58qO2w1lZYe|1||1|1|...........
-+|3757|roKgWqY95V3mXMRzyAjm8D7bLjexpJPvaGDBw826|1||1|1|...........
-+|3633|nJL5lPMwBx23YpqRe0rlKV7damXvWVbOrD4gNzy8|1||1|1|...........
-+|3744|ZmRwd93QL4gaezxEbAxW5O71prn2XjlPvGyqJ6BO|1||1|1|...........
-+|4023|eod9aRWLVl34Gx1Dn7VoaMA2rz6qjgmpEXwQJN5Z|1||1|1|...........
-+|3720|3a5oqJN1bgnx4Ol9dk86NZAByE6jQ8mKDWMpGrLV|1||1|1|...........
-+|3734|EjgWGnXaLy9opPOz20n69V086BlYM3w1deVQvbKr|1||1|1|...........
-+|3741|wvKJdZML6mXP4DzWBAXWN17jxNloa5g23Ve9Y1ry|1||1|1|...........
-+|3721|Nzp2OoJlqn6r1ZgvdA3GWKAabBwP5G4eE3RQmyxD|1||0|0|...........
+node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean|time_of_last_communication:number
++|637|E6Kg9oDnLWyzPRMva7vrqy7Jxp4VG58qO2w1lZYe|3|{"intervals":[{"cct":3000,"value":10,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":20,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":10,"end_time":"13:00","start_time":"05:30"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1733160546993|...........................................................................................................................................................................................................................................................
+-|640|pE5X8NQPaow6vlOZxk6gnw7q42ezGBMyWgDVjR3L|2|{"intervals":[{"cct":3000,"value":10,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":20,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":10,"end_time":"13:00","start_time":"05:30"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1730588947491|.............
++|692|2O14VBzl8aDmWdNw3A518OAGyZ5qLJoEMpj6R9ng|2|{"intervals":[{"cct":3000,"value":10,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":20,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":10,"end_time":"13:00","start_time":"05:30"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1730674756237|.......
++|698|m6EYyZoJ4gWexdjVPARNVLARDOq9wv2N5XzKGplr|1|{"intervals":[{"cct":3000,"value":0,"end_time":"19:40","start_time":"13:00"},{"cct":3000,"value":40,"end_time":"05:30","start_time":"19:40"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1729806347930|.............
+-|638|rDbQ84xzwgdqEoPm3kbJQWk9anOZY1RXyBv2LVM6|3|{"intervals":[{"cct":3000,"value":10,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":20,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":10,"end_time":"13:00","start_time":"05:30"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1730376263529|
++|640|pE5X8NQPaow6vlOZxk6gnw7q42ezGBMyWgDVjR3L|2|{"intervals":[{"cct":3000,"value":0,"end_time":"14:00","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"14:10","start_time":"14:00"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"},{"cct":3000,"value":30,"end_time":"14:20","start_time":"14:10"},{"cct":3000,"value":40,"end_time":"14:30","start_time":"14:20"},{"cct":3000,"value":50,"end_time":"14:40","start_time":"14:30"},{"cct":3000,"value":10,"end_time":"05:30","start_time":"14:40"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|0|1730674754903|.............
++|638|rDbQ84xzwgdqEoPm3kbJQWk9anOZY1RXyBv2LVM6|3|{"intervals":[{"cct":3000,"value":0,"end_time":"14:00","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"14:10","start_time":"14:00"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"},{"cct":3000,"value":30,"end_time":"14:20","start_time":"14:10"},{"cct":3000,"value":40,"end_time":"14:30","start_time":"14:20"},{"cct":3000,"value":50,"end_time":"14:40","start_time":"14:30"},{"cct":3000,"value":10,"end_time":"05:30","start_time":"14:40"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|1|1733160548434|.............
diff --git a/databases/notifications.table b/databases/notifications.table
index a0590d3..8e3788f 100644
--- a/databases/notifications.table
+++ b/databases/notifications.table
@@ -20,9 +20,9 @@ key:string|weight:string|sk:string|en:string
+|power_supply_works_correctly|NOTICE|Napájací zdroj pracuje správne|Power supply works correctly|...............
+|battery_level_is_low|ERROR|Batéria má nízku úroveň napätia|Battery level is low|...............
+|battery_level_is_ok|NOTICE|Batéria má správnu úroveň napätia|Battery level is OK|...............
-+|door_has_been_open|NOTICE|Dvere boli otvorené|Door has been open|...............
-+|door_has_been_closed|NOTICE|Dvere boli zatvorené|Door has been closed|...............
-+|door_has_been_open_without_permision_alarm_is_on|WARNING|Dvere boli otvorené bez povolania - zapnutá siréna|Door has been open without permision - alarm is on|...............
++|door_opened|NOTICE|Dvere boli otvorené|Door has been opeed|...............
++|door_closed|NOTICE|Dvere boli zatvorené|Door has been closed|...............
++|door_opened_without_permission|WARNING|Dvere boli otvorené bez povoeania - zapnutá siréna|Door has been oed without permision - alarm is on|...............
+|state_of_contactor_for_line|INFORMATIONAL|Stav stýkača pre líniu č. ${line} je ${value}|State of contactor for line no. ${line} is ${value}|...............
+|local_database_is_corrupted|CRITICAL|||...............
+|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|...............
@@ -35,3 +35,4 @@ key:string|weight:string|sk:string|en:string
+|lamps_have_turned_on|NOTICE|Lampy sa zapli|Lamps have turned on|...............
+|lamps_have_turned_off|NOTICE|Lampy sa vypli|Lamps have turned off|...............
+|flow_restart|NOTICE|Restart flowu|Flow has been restarted|...............
++|nodes_db_changed|NOTICE|Zmena v node databaze|Node db has changed|...............
diff --git a/databases/pins.table b/databases/pins.table
index f08ec54..825f9b4 100644
--- a/databases/pins.table
+++ b/databases/pins.table
@@ -1,14 +1,14 @@
pin:string|type:string|line:number
-*|input1_01|door_condition|0|...........
-*|input1_02|rotary_switch_state|0|...........
-*|input1_03|rotary_switch_state|0|...........
-*|intut1_04|power_supply|0|...........
-*|input1_05|state_of_main_switch|0|...........
-*|input1_06|state_of_breaker|1|...........
-*|input1_07|state_of_breaker|2|...........
-*|input1_08|state_of_breaker|3|...........
-*|relay1_02|state_of_contactor|1|...........
-*|relay1_03|state_of_contactor|2|...........
-*|relay1_04|state_of_contactor|3|...........
-*|28F46E9D0E00008B|temperature|0|...........
-*|twilight_sensor|twilight_sensor|0|...........
++|1|state_of_main_switch|0|.........
++|2|rotary_switch_state|0|.........
++|3|rotary_switch_state|0|.........
++|4|power_supply|0|.........
++|5|battery|0|.........
++|6|door_condition|0|.........
++|8|state_of_breaker|1|.........
++|9|state_of_breaker|2|.........
++|10|state_of_breaker|3|.........
++|11|state_of_contactor|1|.........
++|12|state_of_contactor|2|.........
++|13|state_of_contactor|3|.........
++|16|twilight_sensor|0|.........
diff --git a/databases/relays.table b/databases/relays.table
index 68e4f06..903d382 100644
--- a/databases/relays.table
+++ b/databases/relays.table
@@ -1,5 +1,6 @@
line:number|tbname:string|contactor:number|profile:string
-+|0|6lQGaY9RDywdVzObj0PadOkPg4NBn3exEK51LWZq|1||...........
-+|1|JzwxZXOvDj1bVrN4nkWw9Qk8qdyBl3MRKLpGPgaQ|1|{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"08:00","start_time":"20:00"},{"value":0,"end_time":"13:00","start_time":"08:00"}],"astro_clock":true,"dawn_lux_sensor":true,"dusk_lux_sensor":true,"dawn_lux_sensor_value":15,"dusk_lux_sensor_value":15,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|...........
-+|2|g9OxBZ5KRwNznlY6pAp6mxkWXvjdEL4eGQobMDy2|1|{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"08:00","start_time":"20:00"},{"value":0,"end_time":"13:00","start_time":"08:00"}],"astro_clock":true,"dawn_lux_sensor":true,"dusk_lux_sensor":true,"dawn_lux_sensor_value":15,"dusk_lux_sensor_value":15,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|...........
-+|3|OzNMgZ9n43qPbjXmy7zWMJA2DKdYvW5e6pxGRrVa|1|{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"08:00","start_time":"20:00"},{"value":0,"end_time":"13:00","start_time":"08:00"}],"astro_clock":true,"dawn_lux_sensor":true,"dusk_lux_sensor":true,"dawn_lux_sensor_value":15,"dusk_lux_sensor_value":15,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|...........
++|0|PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8|1||...........
++|3|52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo|9|{"intervals":[{"value":0,"end_time":"19:30","start_time":"13:00"},{"value":1,"end_time":"05:50","start_time":"19:30"},{"value":0,"end_time":"13:00","start_time":"05:50"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|...........
+-|2|gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM|9||...........
++|1|6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq|9||...........
++|2|gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM|9||............
diff --git a/databases/settings.table b/databases/settings.table
index a182df5..a797615 100644
--- a/databases/settings.table
+++ b/databases/settings.table
@@ -1,2 +1,2 @@
-rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
-+|rvo_senica_39_10.0.0.132|en|28.427B45920702|48.70826502|17.28455203|192.168.252.1|rvo_senica_39_10.0.0.132|qzSNuCNrLP4OL1v47YEe|1883|0|68|unipi|ttyUSB0|1|20|5|...........................................
+rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number
++|testpanel|en|28.427B45920702|48.70826502|17.28455203|192.168.252.1|showroom_test_panel_led|E1QTFLsN4wqyVER5xBaw|1883|0|0|lm|ttymxc4|1|20|5|0.1|3|...............................................
diff --git a/databases/status.table b/databases/status.table
new file mode 100644
index 0000000..da25224
--- /dev/null
+++ b/databases/status.table
@@ -0,0 +1,2 @@
+thermometer:string|em:string|twilight_sensor:string
++|NOK|OK|OK|............
diff --git a/databases/tbdata.nosql b/databases/tbdata.nosql
index e69de29..564a5c3 100644
--- a/databases/tbdata.nosql
+++ b/databases/tbdata.nosql
@@ -0,0 +1,287 @@
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333765,"values":{"maintenance_mode":false}}],"id":"2501279001ax71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333835,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2501279002ax70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333840,"values":{"state_of_main_switch":"closed"}}],"id":"2501279003ax71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333845,"values":{"power_supply":"On"}}],"id":"2501279004ax70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333851,"values":{"battery":"Off"}}],"id":"2501279005ax71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730588333855,"values":{"door_condition":"closed"}}],"id":"2501279006ax70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730588333867,"values":{"status":"OK"}}],"id":"2501279007ax71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730588333873,"values":{"statecode":2}}],"id":"2501279008ax70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730588333876,"values":{"state_of_breaker":"On"}}],"id":"2501279009ax71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730588333881,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2501279010ax70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730588333885,"values":{"status":"OK"}}],"id":"2501279011ax71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730588333887,"values":{"statecode":2}}],"id":"2501279012ax70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730588333890,"values":{"state_of_breaker":"On"}}],"id":"2501279013ax71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730588333893,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2501279014ax70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730588333896,"values":{"status":"OK"}}],"id":"2501279015ax71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730588333899,"values":{"statecode":2}}],"id":"2501279016ax70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730588333901,"values":{"state_of_breaker":"On"}}],"id":"2501279017ax71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728172,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2501302001ny71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728240,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2501302002ny70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728246,"values":{"state_of_main_switch":"closed"}}],"id":"2501302003ny71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728251,"values":{"power_supply":"On"}}],"id":"2501302004ny70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728256,"values":{"battery":"Off"}}],"id":"2501302005ny71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730589728260,"values":{"door_condition":"closed"}}],"id":"2501302006ny70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730589728272,"values":{"status":"OK"}}],"id":"2501302007ny71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730589728278,"values":{"statecode":2}}],"id":"2501302008ny70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730589728281,"values":{"state_of_breaker":"On"}}],"id":"2501302009ny71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730589728286,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2501302010ny70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730589728290,"values":{"status":"OK"}}],"id":"2501302011ny71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730589728293,"values":{"statecode":2}}],"id":"2501302012ny70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730589728295,"values":{"state_of_breaker":"On"}}],"id":"2501302013ny71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730589728299,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2501302014ny70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730589728302,"values":{"status":"OK"}}],"id":"2501302015ny71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730589728305,"values":{"statecode":2}}],"id":"2501302016ny70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730589728307,"values":{"state_of_breaker":"On"}}],"id":"2501302017ny71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126776,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2501309001xk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126844,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2501309002xk70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126850,"values":{"state_of_main_switch":"closed"}}],"id":"2501309003xk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126855,"values":{"power_supply":"On"}}],"id":"2501309004xk70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126860,"values":{"battery":"Off"}}],"id":"2501309005xk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730590126865,"values":{"door_condition":"closed"}}],"id":"2501309006xk70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730590126877,"values":{"status":"OK"}}],"id":"2501309007xk71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730590126883,"values":{"statecode":2}}],"id":"2501309008xk70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730590126886,"values":{"state_of_breaker":"On"}}],"id":"2501309009xk71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730590126891,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2501309010xk70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730590126895,"values":{"status":"OK"}}],"id":"2501309011xk71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730590126897,"values":{"statecode":2}}],"id":"2501309012xk70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730590126900,"values":{"state_of_breaker":"On"}}],"id":"2501309013xk71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730590126903,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2501309014xk70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730590126906,"values":{"status":"OK"}}],"id":"2501309015xk71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730590126909,"values":{"statecode":2}}],"id":"2501309016xk70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730590126911,"values":{"state_of_breaker":"On"}}],"id":"2501309017xk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591367948,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2501329001ua71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591368017,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2501329002ua70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591368022,"values":{"state_of_main_switch":"closed"}}],"id":"2501329003ua71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591368028,"values":{"power_supply":"On"}}],"id":"2501329004ua70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591368032,"values":{"battery":"Off"}}],"id":"2501329005ua71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730591368037,"values":{"door_condition":"closed"}}],"id":"2501329006ua70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730591368049,"values":{"status":"OK"}}],"id":"2501329007ua71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730591368055,"values":{"statecode":2}}],"id":"2501329008ua70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730591368058,"values":{"state_of_breaker":"On"}}],"id":"2501329009ua71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105058,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2501342001ch71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105130,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2501342002ch70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105135,"values":{"state_of_main_switch":"closed"}}],"id":"2501342003ch71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105140,"values":{"power_supply":"On"}}],"id":"2501342004ch70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105145,"values":{"battery":"Off"}}],"id":"2501342005ch71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105150,"values":{"door_condition":"closed"}}],"id":"2501342006ch70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730592105162,"values":{"status":"OK"}}],"id":"2501342007ch71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730592105168,"values":{"statecode":2}}],"id":"2501342008ch70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730592105171,"values":{"state_of_breaker":"On"}}],"id":"2501342009ch71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730592105176,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2501342010ch70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730592105180,"values":{"status":"OK"}}],"id":"2501342011ch71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730592105182,"values":{"statecode":2}}],"id":"2501342012ch70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730592105185,"values":{"state_of_breaker":"On"}}],"id":"2501342013ch71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730592105188,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2501342014ch70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730592105191,"values":{"status":"OK"}}],"id":"2501342015ch71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730592105194,"values":{"statecode":2}}],"id":"2501342016ch70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730592105196,"values":{"state_of_breaker":"On"}}],"id":"2501342017ch71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592105200,"values":{"twilight_sensor":31}}],"id":"2501342018ch70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730592420656,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2501347001nd71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730663586542,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502533001gt71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730671706506,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502668001yg71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672433386,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 2 : on","message_data":""}}}],"id":"2502681003ad71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672433494,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is On","message_data":""}}}],"id":"2502681004ad70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672433568,"values":{"statecode":0}}],"id":"2502681005ad71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672433588,"values":{"state_of_contactor":true }}],"id":"2502681006ad70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672433849,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : on","message_data":""}}}],"id":"2502681007ad71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672433892,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is On","message_data":""}}}],"id":"2502681008ad70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672433908,"values":{"statecode":0}}],"id":"2502681009ad71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672433910,"values":{"state_of_contactor":true }}],"id":"2502681010ad70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777712,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502686001di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777782,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2502686002di70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777787,"values":{"state_of_main_switch":"closed"}}],"id":"2502686003di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777792,"values":{"power_supply":"On"}}],"id":"2502686004di70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777798,"values":{"battery":"Off"}}],"id":"2502686005di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777802,"values":{"door_condition":"closed"}}],"id":"2502686006di70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672777814,"values":{"status":"OK"}}],"id":"2502686007di71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672777820,"values":{"statecode":2}}],"id":"2502686008di70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672777824,"values":{"state_of_breaker":"On"}}],"id":"2502686009di71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672777828,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2502686010di70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672777832,"values":{"status":"OK"}}],"id":"2502686011di71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672777835,"values":{"statecode":2}}],"id":"2502686012di70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672777837,"values":{"state_of_breaker":"On"}}],"id":"2502686013di71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672777841,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2502686014di70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672777844,"values":{"status":"OK"}}],"id":"2502686015di71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672777847,"values":{"statecode":2}}],"id":"2502686016di70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672777849,"values":{"state_of_breaker":"On"}}],"id":"2502686017di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777872,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2502686018di70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672777883,"values":{"state_of_contactor":false}}],"id":"2502686019di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777888,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2502686020di70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672777895,"values":{"state_of_contactor":false}}],"id":"2502686021di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672777899,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2502686022di70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672777905,"values":{"state_of_contactor":false}}],"id":"2502686023di71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672922976,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502689001nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923046,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2502689002nu70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923052,"values":{"state_of_main_switch":"closed"}}],"id":"2502689003nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923057,"values":{"power_supply":"On"}}],"id":"2502689004nu70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923062,"values":{"battery":"Off"}}],"id":"2502689005nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923066,"values":{"door_condition":"closed"}}],"id":"2502689006nu70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672923078,"values":{"status":"OK"}}],"id":"2502689007nu71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672923084,"values":{"statecode":2}}],"id":"2502689008nu70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672923088,"values":{"state_of_breaker":"On"}}],"id":"2502689009nu71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672923092,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2502689010nu70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672923096,"values":{"status":"OK"}}],"id":"2502689011nu71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672923099,"values":{"statecode":2}}],"id":"2502689012nu70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672923101,"values":{"state_of_breaker":"On"}}],"id":"2502689013nu71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672923105,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2502689014nu70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672923108,"values":{"status":"OK"}}],"id":"2502689015nu71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672923111,"values":{"statecode":2}}],"id":"2502689016nu70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672923113,"values":{"state_of_breaker":"On"}}],"id":"2502689017nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923136,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2502689018nu70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730672923147,"values":{"state_of_contactor":false}}],"id":"2502689019nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923152,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2502689020nu70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730672923159,"values":{"state_of_contactor":false}}],"id":"2502689021nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730672923164,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2502689022nu70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730672923170,"values":{"state_of_contactor":false}}],"id":"2502689023nu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534730,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502699001wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534807,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2502699002wb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534812,"values":{"state_of_main_switch":"closed"}}],"id":"2502699003wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534818,"values":{"power_supply":"On"}}],"id":"2502699004wb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534823,"values":{"battery":"Off"}}],"id":"2502699005wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534827,"values":{"door_condition":"closed"}}],"id":"2502699006wb70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730673534840,"values":{"status":"OK"}}],"id":"2502699007wb71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730673534846,"values":{"statecode":2}}],"id":"2502699008wb70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730673534849,"values":{"state_of_breaker":"On"}}],"id":"2502699009wb71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730673534854,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2502699010wb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730673534857,"values":{"status":"OK"}}],"id":"2502699011wb71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730673534860,"values":{"statecode":2}}],"id":"2502699012wb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730673534863,"values":{"state_of_breaker":"On"}}],"id":"2502699013wb71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730673534866,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2502699014wb70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730673534869,"values":{"status":"OK"}}],"id":"2502699015wb71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730673534872,"values":{"statecode":2}}],"id":"2502699016wb70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730673534875,"values":{"state_of_breaker":"On"}}],"id":"2502699017wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534918,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2502699018wb70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730673534942,"values":{"state_of_contactor":false}}],"id":"2502699019wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534956,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2502699020wb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730673534963,"values":{"state_of_contactor":false}}],"id":"2502699021wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730673534968,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2502699022wb70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730673534974,"values":{"state_of_contactor":false}}],"id":"2502699023wb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730675467314,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502731001jm71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730676458104,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 2 : off","message_data":""}}}],"id":"2502748003ji71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730676458279,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : off","message_data":""}}}],"id":"2502748004ji70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615197,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2502783001xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615259,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2502783002xe70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615264,"values":{"state_of_main_switch":"closed"}}],"id":"2502783003xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615270,"values":{"power_supply":"On"}}],"id":"2502783004xe70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615276,"values":{"battery":"Off"}}],"id":"2502783005xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615281,"values":{"door_condition":"closed"}}],"id":"2502783006xe70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730678615307,"values":{"status":"OK"}}],"id":"2502783007xe71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730678615313,"values":{"statecode":2}}],"id":"2502783008xe70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730678615316,"values":{"state_of_breaker":"On"}}],"id":"2502783009xe71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730678615321,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2502783010xe70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730678615324,"values":{"status":"OK"}}],"id":"2502783011xe71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730678615327,"values":{"statecode":2}}],"id":"2502783012xe70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730678615329,"values":{"state_of_breaker":"On"}}],"id":"2502783013xe71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730678615333,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2502783014xe70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730678615336,"values":{"status":"OK"}}],"id":"2502783015xe71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730678615338,"values":{"statecode":2}}],"id":"2502783016xe70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730678615340,"values":{"state_of_breaker":"On"}}],"id":"2502783017xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615396,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2502783018xe70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730678615433,"values":{"state_of_contactor":false}}],"id":"2502783019xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615453,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2502783020xe70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730678615470,"values":{"state_of_contactor":false}}],"id":"2502783021xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615487,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2502783022xe70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730678615506,"values":{"state_of_contactor":false}}],"id":"2502783023xe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730678615510,"values":{"twilight_sensor":31}}],"id":"2502783024xe70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730757867671,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2504104001au71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759363143,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : on","message_data":""}}}],"id":"2504129003fe71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759363792,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is On","message_data":""}}}],"id":"2504129004fe70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759363814,"values":{"statecode":0}}],"id":"2504129005fe71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759363817,"values":{"state_of_contactor":true }}],"id":"2504129006fe70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583799,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2504133001fr71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583910,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"NOK","statecode":34}}],"id":"2504133002fr70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583920,"values":{"state_of_main_switch":"closed"}}],"id":"2504133003fr71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583925,"values":{"power_supply":"On"}}],"id":"2504133004fr70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583930,"values":{"battery":"Off"}}],"id":"2504133005fr71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759583947,"values":{"door_condition":"closed"}}],"id":"2504133006fr70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730759583960,"values":{"status":"OK"}}],"id":"2504133007fr71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730759583965,"values":{"statecode":2}}],"id":"2504133008fr70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1730759583968,"values":{"state_of_breaker":"On"}}],"id":"2504133009fr71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730759583974,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2504133010fr70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730759583977,"values":{"status":"OK"}}],"id":"2504133011fr71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730759583980,"values":{"statecode":2}}],"id":"2504133012fr70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1730759583982,"values":{"state_of_breaker":"On"}}],"id":"2504133013fr71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759583986,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2504133014fr70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759583989,"values":{"status":"OK"}}],"id":"2504133015fr71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759583991,"values":{"statecode":2}}],"id":"2504133016fr70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759583993,"values":{"state_of_breaker":"On"}}],"id":"2504133017fr71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759985331,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : on","message_data":""}}}],"id":"2504140003mc71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730759985367,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is On","message_data":""}}}],"id":"2504140004mc70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759985398,"values":{"statecode":0}}],"id":"2504140005mc71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1730759985410,"values":{"state_of_contactor":true }}],"id":"2504140006mc70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1730761965548,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2504172001np71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731876994929,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522756001rh71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731877329335,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : on","message_data":""}}}],"id":"2522762003cs71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731877329409,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is On","message_data":""}}}],"id":"2522762004cs70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731877329460,"values":{"statecode":0}}],"id":"2522762005cs71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731877329478,"values":{"state_of_contactor":true }}],"id":"2522762006cs70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106215,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522775001tb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106280,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"OK","statecode":34}}],"id":"2522775002tb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106285,"values":{"state_of_main_switch":"closed"}}],"id":"2522775003tb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106322,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2522775004tb70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878106365,"values":{"statecode":3}}],"id":"2522775005tb71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878106370,"values":{"state_of_contactor":false}}],"id":"2522775006tb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106380,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2522775007tb71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106387,"values":{"statecode":3}}],"id":"2522775008tb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106391,"values":{"state_of_contactor":false}}],"id":"2522775009tb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106398,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2522775010tb70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731878106404,"values":{"statecode":3}}],"id":"2522775011tb71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731878106407,"values":{"state_of_contactor":false}}],"id":"2522775012tb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106413,"values":{"power_supply":"On"}}],"id":"2522775013tb71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106417,"values":{"battery":"Off"}}],"id":"2522775014tb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878106420,"values":{"door_condition":"closed"}}],"id":"2522775015tb71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878106425,"values":{"status":"OK"}}],"id":"2522775016tb70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878106428,"values":{"statecode":2}}],"id":"2522775017tb71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878106430,"values":{"state_of_breaker":"On"}}],"id":"2522775018tb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106434,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2522775019tb71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106436,"values":{"status":"OK"}}],"id":"2522775020tb70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106439,"values":{"statecode":2}}],"id":"2522775021tb71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731878106441,"values":{"state_of_breaker":"On"}}],"id":"2522775022tb70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260010,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522777001wk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260073,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"OK","statecode":34}}],"id":"2522777002wk70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260077,"values":{"state_of_main_switch":"closed"}}],"id":"2522777003wk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260083,"values":{"power_supply":"On"}}],"id":"2522777004wk70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260088,"values":{"battery":"Off"}}],"id":"2522777005wk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878260092,"values":{"door_condition":"closed"}}],"id":"2522777006wk70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878260104,"values":{"status":"OK"}}],"id":"2522777007wk71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878260110,"values":{"statecode":2}}],"id":"2522777008wk70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731878260113,"values":{"state_of_breaker":"On"}}],"id":"2522777009wk71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731878386415,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522780001uh71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121143,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522825001pn71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121208,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"OK","statecode":34}}],"id":"2522825002pn70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121213,"values":{"state_of_main_switch":"closed"}}],"id":"2522825003pn71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121226,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 1 is Off","message_data":""}}}],"id":"2522825004pn70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731881121245,"values":{"statecode":3}}],"id":"2522825005pn71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731881121249,"values":{"state_of_contactor":false}}],"id":"2522825006pn70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121256,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 2 is Off","message_data":""}}}],"id":"2522825007pn71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121263,"values":{"statecode":3}}],"id":"2522825008pn70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121266,"values":{"state_of_contactor":false}}],"id":"2522825009pn71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121273,"values":{"_event":{"type":"informational","status":"new","source":{"func":"switchLogic","component":"1730323243484","component_name":"DIDO_Controller","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: State of contactor for line no. 3 is Off","message_data":""}}}],"id":"2522825010pn70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121280,"values":{"statecode":3}}],"id":"2522825011pn71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121282,"values":{"state_of_contactor":false}}],"id":"2522825012pn70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121288,"values":{"power_supply":"On"}}],"id":"2522825013pn71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121293,"values":{"battery":"Off"}}],"id":"2522825014pn70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731881121297,"values":{"door_condition":"closed"}}],"id":"2522825015pn71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731881121302,"values":{"status":"OK"}}],"id":"2522825016pn70b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731881121305,"values":{"statecode":2}}],"id":"2522825017pn71b"}
+-"6lQGaY9RDywdVzObj0P1vrkPg4NBn3exEK51LWZq":[{"ts":1731881121308,"values":{"state_of_breaker":"On"}}],"id":"2522825018pn70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121311,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM"},"message":"testpanel: Circuit breaker was turned on - line no. 2","message_data":""}}}],"id":"2522825019pn71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121314,"values":{"status":"OK"}}],"id":"2522825020pn70b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121316,"values":{"statecode":2}}],"id":"2522825021pn71b"}
+-"gP1eOZVj3Q9lv5aDEk4EVP7rdpqW8yLm2BbKzJxM":[{"ts":1731881121318,"values":{"state_of_breaker":"On"}}],"id":"2522825022pn70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121347,"values":{"_event":{"type":"notice","status":"new","source":{"func":"CMD Manager: onData","component":"1619515097737","component_name":"CMD Manager","edge":"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo"},"message":"testpanel: Circuit breaker was turned on - line no. 3","message_data":""}}}],"id":"2522825023pn71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121353,"values":{"status":"OK"}}],"id":"2522825024pn70b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121360,"values":{"statecode":2}}],"id":"2522825025pn71b"}
+-"52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo":[{"ts":1731881121362,"values":{"state_of_breaker":"On"}}],"id":"2522825026pn70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884700377,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522885001lo71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884700441,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"OK","statecode":34}}],"id":"2522885002lo70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884700446,"values":{"state_of_main_switch":"closed"}}],"id":"2522885003lo71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884700451,"values":{"power_supply":"On"}}],"id":"2522885004lo70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884700455,"values":{"battery":"Off"}}],"id":"2522885005lo71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731884854298,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522887001ap71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731885414928,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : off","message_data":""}}}],"id":"2522897013ln71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731885415091,"values":{"_event":{"type":"informational","status":"new","source":{"func":"CMD Manager: process cmd","component":"1619515097737","component_name":"CMD Manager","edge":"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8"},"message":"testpanel: Switching profile point applied to line no. 3 : off","message_data":""}}}],"id":"2522897014ln70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1731885602197,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2522900001jc71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1732040930566,"values":{"edge_fw_version":"2024-10-14","maintenance_mode":false}}],"id":"2525489001lu71b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1732040930629,"values":{"electrometer_status":1,"twilight_sensor_status":1,"thermometer_status":0,"phase_1_status":1,"phase_2_status":1,"phase_3_status":1,"master_node_status":1,"status":"OK","statecode":34}}],"id":"2525489002lu70b"}
+-"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8":[{"ts":1732040930634,"values":{"state_of_main_switch":"closed"}}],"id":"2525489003lu71b"}
diff --git a/flow/audit_test_panel.csv b/flow/audit_test_panel.csv
deleted file mode 100644
index 907a6a9..0000000
--- a/flow/audit_test_panel.csv
+++ /dev/null
@@ -1,48 +0,0 @@
-LumDimm;NODE (HEX);NODE (DEC);Line;TB name
-1;299;665;3;gbv4nzqxW0XGAPKVNk8kr25ZQ2l3O6LRBprM97ew
-2;28A;650;3;0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO
-3;296;662;3;gbv4nzqxW0XGAPKVNk8kW48ZQ2l3O6LRBprM97ew
-4;297;663;1;LpkVlmq4b3jMwJQxBZ8akayrXAP6o97Ke0aOYEg2
-5;29C;668;3;lekrmdvO0BQG1ZW4AV8jeZ5M39xnN2wEbRgPjXLp
-6;2B1;689;3;q0rElBPdL6kxMAjnzVDRl95emNZY7oOv2wK9gb31
-7;2AB;683;3;XKQbz3WAwY21dGa0R453rWyJm9PZOjqlvpr6Nkeo
-8;2B0;688;3;PaGbQ3wBAZWOmRvK9VDpvz5endLJYopEqlkzNMxX
-9;2B9;697;3;joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM
-10;293;659;3;Ymn9oleRxJ0vw17WzAyGwdyEBk4ObdMXj2VgpNLG
-11;294;660;3;gj7zbKV46oQ1p2e0AJ8XqZDG3YNWaRrlOEXvBxmM
-12;295;661;3;laYK7Pomn2bNZXEpedDxAqyOJkQ3WwV49gqxLrAR
-13;2A0;672;2;0XYElWeKBNJn1gdoMG8lON5ALkPvj4V3xra2q6mO
-14;2B4;692;2;l9YkRpoB2vVa0mKqEO8ZGGDjW43eXnJML6GxzbwQ
-15;2B2;690;2;wGjQobgOK0n2YqBZmVDVR3DR9ep6EXA1ka3vzlP7
-16;27C;636;2;M6ogKQW09bOXewAYvZyvJqyJrV1aRnPGE37p42Nx
-17;27B;635;2;Vq2JaWpw1OdBKmNeoj8w605XE40l3kgL76Azb9QP
-18;2B6;694;2;Jm32GR1qpwQxlZza0N5mE15AP96YbOKLogrXVW4e
-19;2B5;693;2;KjbN4q7JPZmexgdnz2yKdn5YAWwO0Q3BMX6ERLoV
-20;2B3;691;1;lekrmdvO0BQG1ZW4AV8jzq8M39xnN2wEbRgPjXLp
-21;27F;639;3;BOjEzGRZ46bnp9wa2A8z76D0JkmW1QPNdrqevXVL
-22;27E;638;3;9xgzG4Op1BrKZPmoQkDrmj8E73ndJNMjavAwX2Re
-23;27D;637;3;koW06PeGrLlBp2YJQE5Ogw5RmMaXKzj3wOAZg9n7
-24;28F;655;2;RMgnK93rkoAazbqdQ4yBYpDZ1YXGx6pmwBeVEP2O
-25;288;648;2;gaMGN4x1e9JlZz0QPRDd9Rym6dVr3OpvqKnoWBbk
-26;298;664;1;oGVzxNWP9lrjaQ7vKODQ7g51gqp62YZREmdw3XBM
-27;29F;671;3;AvVdgzYJZaPx3oMqeED4Oj8NnmKkw716bRO90jLB
-28;280;640;2;WjBL12pg63eX4N9P7zy0XYyEJKmlbkGwZMx0avQV
-29;28B;651;2;qaAOzENGrvpbe0VoK7D6Ld519PZmdg3nl24JLQMk
-30;27A;634;2;NGWamnYqlP1wbgrZQxDAWm5e2X7OVAK69koR04vL
-31;29E;670;2;dlE1VQjYrNx9gZRmb38g1YyoLBO4qaAk2M6JPnG7
-32;281;641;2;vnmG4kJxaXWNBgMQq0D7Mz5e9oZzOAlr6LdR3w2V
-33;278;632;2;LpkVlmq4b3jMwJQxBZ8aM78rXAP6o97Ke0aOYEg2
-34;29D;669;3;Y9aLW03wOZkABvKXbMyL0lyV1xdNj72r4egqGRzJ
-35;2A8;680;1;KL2jNOVpdARa9XvoeJDPga8bkmPBxqn7Ww3gzGQ1
-36;2BA;698;1;mYnBzbeGaAL62jowRv59M35Xq9QpZ0K7O1dg4xVl
-37;29B;667;1;MzXBoWbEZjO0lrpqnRyoJ4DkmVeaNAGdL9g4QKxP
-38;289;649;1;0p2rwdP7aGoOQLJNgAynJNy6xWXbmMe3nvZqlzkV
-39;290;656;1;BrQx3NGKgVMRaXYAo9y1GE8ZzkWnj1le6bdOLE20
-40;2AA;682;1;vnreBJ6PMqgz20pYEL82XQyG1jkWwdQxZVNAOlmK
-41;285;645;1;jklN4JpQAx362o9XYZDN6wDgrWw1P7GEbdBM0vRV
-42;283;643;1;oZmYXEbw9lVWRv1jLxDe9bDdgAMz4PKQnNJ6eB23
-43;282;642;1;pEonaKBOGbj9034MgJ8W3G8qXvxNWVkAPQz21R6L
-44;287;647;1;BLQal6Pn9oz1KmNgek5Yqd50vd2MAbqG3OV7Rp4j
-45;286;646;1;4agVJ9dPQkmp1R2X3EDJKxyrK6ZlNoM0n7qxBOev
-46;29A;666;1;9PpgLEnvk4WMV6RmOJybMGDaeAXzo2BQNG3K17Zw
-47;28E;654;1;Mmp93b2nvd7OoqgBeEyEZq5kjlAV1Y4ZNXwW0zLG
diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js
index 48b4987..ed4a928 100644
--- a/flow/cmd_manager.js
+++ b/flow/cmd_manager.js
@@ -3,14 +3,10 @@ exports.title = 'CMD Manager';
exports.group = 'Worksys';
exports.color = '#5D9CEC';
exports.version = '0.0.3';
-exports.output = ['red', 'blue', 'yellow', 'blue', 'white'];
-
//blue - send message to relays
-
-exports.input = true;
-exports.author = 'Daniel Segeš';
+exports.output = ['red', 'blue', 'yellow', 'blue', 'white'];
+exports.input = 3;
exports.icon = 'cloud-upload';
-//exports.npm = ['serialport' , 'child_process'];
exports.html = `
@@ -30,802 +26,709 @@ exports.html = `
`;
-
exports.readme = `Manager for CMD calls`;
-const SerialPort = require('serialport');
-const { exec } = require('child_process');
-const { crc8, crc16, crc32 } = require('easy-crc');
-const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js');
-const { bytesToInt, longToByteArray, addZeroBefore, isEmptyObject, convertUTCDateToLocalDate } = require('./helper/utils');
-const bitwise = require('bitwise');
-
-var SunCalc = require('./helper/suncalc.js');
-const DataToTbHandler = require('./helper/DataToTbHandler.js');
-const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
-const { promisifyBuilder, makeMapFromDbResult} = require('./helper/db_helper.js');
-const { sendNotification, initNotifications, ERRWEIGHT } = require('./helper/notification_reporter.js');
-
-const dbNodes = TABLE("nodes");
-const dbRelays = TABLE("relays");
-const dbSettings = TABLE("settings");
-
-//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
-//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
-var path = require('path');
-var log4js = require("log4js");
-const process = require('process');
-
-//TODO - to remove?
-// runTasks intervals
-const SHORT_INTERVAL = 30;
-const LONG_INTERVAL = 300;
-
-//send data to following instances:
-const SEND_TO = {
- debug: 0,
- tb: 1,
- http_response: 2,
- dido_controller: 3,
- infoSender: 4
-}
-
-const PRIORITY_TYPES = {
- terminal: 0,
- fw_detection: 1,//reserved only for FW detection - FLOW.OMS_masterNodeIsResponding
- high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
- relay_profile: 3,
- node_broadcast: 4,
- node_profile: 5,
- node_cmd: 6
-}
-
-//list of command calls to process. Processing in runTasks function
-let tasks = [];
-
-let interval = null;//timeout for procesing tasks
-let refFlowdata = null;//holds reference to httprequest flowdata
-let refFlowdataObj = {};
-
-//load from settings
-let latitude = 48.70826502;//48.682255758;
-let longitude = 17.28455203;//17.278910807;
-
-const gmtOffset = 0;
-
-//ak nie je nastaveny
-//https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
-//https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
-
-//priorities for registers
-let priorities = [];
-
-let minutes = 1;
-priorities["0"] = minutes;
-priorities["1"] = minutes;
-
-minutes = 5;
-priorities["74"] = minutes;
-priorities["75"] = minutes;
-priorities["76"] = minutes;
-priorities["77"] = minutes;
-priorities["78"] = minutes;
-priorities["79"] = minutes;
-priorities["84"] = minutes;
-
-minutes = 10;
-priorities["87"] = minutes;
-priorities["6"] = minutes;
-priorities["7"] = minutes;
-priorities["80"] = minutes;
-priorities["8"] = minutes;
-priorities["3"] = minutes;
-priorities["89"] = minutes;
-
-//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
-let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89];
-
-const errorHandler = new ErrorToServiceHandler();
-
-let rotary_switch_state = "Off";
-let lux_sensor;
-let state_of_breaker = {};//key is line, value is On/Off
-let disconnectedReport = {};//key is tbname, value true/false
-
-let relaysData = {};//key is line, value is data from db
-let nodesData = {};//key is node, value data from db
-
-//helper container for counting resolved group of commands (commands related to set profile)
-let cmdCounter = {};//key is node, value is counter
-let cmdNOKNodeCounter = {};//key is node, value is counter
-
-//END OF VARIABLE SETTINGS
-//--------------------------------
-
-
-log4js.configure({
- appenders: {
- errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
- console: { type: 'console' }
- },
- categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
- }
-});
-
-const errLogger = log4js.getLogger("errLogs");
-const logger = log4js.getLogger();
-const monitor = log4js.getLogger("monitorLogs");
-
-//USAGE
-//logger.debug("text")
-//monitor.info('info');
-//errLogger.error("some error");
-
-
-function cmdCounterResolve(address)
-{
- if(cmdCounter.hasOwnProperty(address))
- {
- cmdCounter[address] = cmdCounter[address] - 1;
-
- let result = cmdCounter[address];
- if(result == 0) delete cmdCounter[address];
- return result;
- }
- return -1;
-}
-
-
-function getParams(priority)
-{
- let params = {};
-
- //core rpc values
- params.address = 0;//if(recipient === 0) address = 0;
- params.byte1 = 0;//msb, podla dokumentacie data3
- params.byte2 = 0;//podla dokumentacie data2
- params.byte3 = 0;//podla dokumentacie data1
- params.byte4 = 0;//lsb, podla dokumentacie data0
- params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
- params.register = -1;//register number
- params.rw = 0;//0: read, 1: write
-
- //other values
- //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles" "edge_date_time" "number_of_luminaires"
- //params.tbname = tbname;
- params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
- params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
- if(priority != undefined )
- {
- params.timestamp = priority;
- params.priority = priority;
- }
-
- params.addMinutesToTimestamp = 0;//repeat task if value is > 0,
-
- //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
- //params.info = "";
-
- return params;
-}
-
-
-async function loadSettings()
-{
- let responseSettings = await promisifyBuilder(dbSettings.find());
-
- latitude = responseSettings[0]["latitude"];
- longitude = responseSettings[0]["longitude"];
-
- //globals
- FLOW.OMS_language = responseSettings[0]["lang"];
- FLOW.OMS_rvo_name = responseSettings[0]["rvo_name"];
- FLOW.OMS_projects_id = responseSettings[0]["projects_id"];
- //FLOW.OMS_rvo_tbname = responseSettings[0]["tbname"];
- FLOW.OMS_temperature_adress = responseSettings[0]["temperature_adress"];
- FLOW.OMS_controller_type = responseSettings[0]["controller_type"];
- FLOW.OMS_serial_port = responseSettings[0]["serial_port"];
-
- //logger.debug('settings', responseSettings[0]);
-
- initNotifications();
-}
-
-loadSettings();
-
-
-async function loadNodes()
-{
- const responseNodes = await promisifyBuilder(dbNodes.find());
- nodesData = makeMapFromDbResult(responseNodes, "node");
-}
-
-loadNodes();
-
-
-//nastav profil nodu
-function processNodeProfile(node)
-{
- if(rotary_switch_state != "Automatic")
- {
- logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
- return;
- }
-
- let nodeObj = nodesData[node];
- let line = nodeObj.line;
-
- if(relaysData[line].contactor == 0)
- {
- logger.debug("line line is off", line, node);
- return;
- }
-
- if(nodeObj.processed == 1)
- {
- logger.debug("node was already processed", node);
- return;
- }
-
- let profile = nodeObj.profile;
-
- logger.debug("processNodeProfile: start - set profile for ", node, profile);
-
- let nodeProfile;
- try{
- nodeProfile = JSON.parse( profile );
- if(Object.keys(nodeProfile).length === 0) throw ("profile is not defined");
- } catch (error) {
- logger.debug("Error parsing node profile", error);
- }
-
- logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
-
- let timestamp = PRIORITY_TYPES.node_cmd;
-
- removeTask({type: "set_node_profile", address: node});
- cmdNOKNodeCounter[node] = 0;
-
- //co ked sa prave spracovava?
- //if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
-
- if(nodeProfile === undefined)
- {
- //vypneme profil nodu, posleme cmd
- //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
- //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
-
- logger.debug("turn off profile");
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = 0;
- params.byte2 = 0;
- params.byte3 = 0;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'turn off/reset node profile';
-
- cmdCounter[node] = 1;
-
- tasks.push(params);
-
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", SEND_TO.tb, instance );
- }
- else
- {
- let tasksProfile = [];
- //cmdCounter[node] = tasksProfile.length;
- //tasks.push(tasksProfile);
-
- //let timestamp = PRIORITY_TYPES.node_cmd;
-
- //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = 0;
- params.byte2 = 0;
- params.byte3 = 0;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'turn off node profile';
-
- tasksProfile.push(params);
-
- timestamp++;
-
- logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
-
- //TS1 Time point a TS1 Time Point Levels
- let register = 9;
- for(let i = 0; i < nodeProfile.intervals.length; i++)
- {
- let obj = nodeProfile.intervals[i];
- //let timePoint = obj.time_point;
- let dim_value = obj.value;
-
-
- //Reg 9 až Reg 40
-
- /*
- Samotný profil sa zapisuje do max. 16 párov – časový bod a úroveň.
- Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF (táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8).
- Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13:00.
- Časový bod má formát:
- Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované
- Register úrovne má rovnaký formát ako dimming register (Reg 1).
- */
-
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- //params.byte1 = 0;//msb, podla dokumentacie data3
- //params.byte2 = 0;//podla dokumentacie data2
- //params.byte3 = 0;//podla dokumentacie data1
- //params.byte4 = 0;//lsb, podla dokumentacie data0
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- let start_time = obj.start_time;
- let t = start_time.split(":");
- //if(timePoint != undefined) t = timePoint.split(":");
- //else t = [0,0];
-
- logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = parseInt(t[0]);//hh
- params.byte2 = parseInt(t[1]);//mm
- params.byte3 = 0;//ss
- params.byte4 = 0;//
- params.recipient = 1;
- params.register = register;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'TS1 Time point ' + (i + 1);
-
- tasksProfile.push(params);
-
- register++;
- timestamp++;
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = 0;
- params.byte2 = 0;
- params.byte3 = 0;//ss
- params.byte4 = parseInt(dim_value) + 128;//
- params.recipient = 1;
- params.register = register;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'TS1 Time point Levels ' + (i + 1);
-
- tasksProfile.push(params);
-
- register++;
- timestamp++;
- }
-
- //Threshold lux level for DUSK/DAWN
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- //params.byte1 = 0;//msb, podla dokumentacie data3
- //params.byte2 = 0;//podla dokumentacie data2
- //params.byte3 = 0;//podla dokumentacie data1
- //params.byte4 = 0;//lsb, podla dokumentacie data0
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-
- //Time schedule settings na koniec
- //if(nodeProfile.dusk_lux_sensor || nodeProfile.dawn_lux_sensor)
- {
-
- logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 96;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = "Threshold lux level for DUSK/DAWN";
-
- if(nodeProfile.dusk_lux_sensor)
- {
- let v = nodeProfile.dusk_lux_sensor_value;
- let ba = longToByteArray(v);
-
- params.byte1 = ba[1];//msb
- params.byte2 = ba[0];
- }
-
- if(nodeProfile.dawn_lux_sensor)
- {
- let v = nodeProfile.dawn_lux_sensor_value;
- let ba = longToByteArray(v);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- }
-
- tasksProfile.push(params);
- timestamp++;
-
- }
-
- //DUSK/DAWN max. adjust period
- {
-
- logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node);
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 97;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = "DUSK/DAWN max. adjust period";
-
- if(nodeProfile.astro_clock)
- {
- let v = nodeProfile.dusk_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte1 = ba[1];//msb
- params.byte2 = ba[0];
- }
-
- if(nodeProfile.astro_clock)
- {
- let v = nodeProfile.dawn_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- }
-
- tasksProfile.push(params);
- timestamp++;
-
- }
-
- //Static offset
- {
-
- //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
- //Bity 0 – 6: hodnota v minútach
- //Bit 7: znamienko (1 – mínus)
-
- logger.debug("processNodeProfile: Static offset", node);
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 98;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = "Static offset";
-
- if(nodeProfile.astro_clock)
- {
- let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
- let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
-
- if(dusk_astro_clock_offset < 0)
- {
- params.byte3 = (dusk_astro_clock_offset * -1) + 128;
- }
- else
- {
- params.byte3 = dusk_astro_clock_offset;
- }
-
- if(dawn_astro_clock_offset < 0)
- {
- params.byte4 = (dawn_astro_clock_offset * -1) + 128;
- }
- else
- {
- params.byte4 = dawn_astro_clock_offset;
- }
- }
-
- tasksProfile.push(params);
- timestamp++;
- }
-
- logger.debug("Time schedule settings - turn on", node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 8;
- params.recipient = 1;
- params.rw = 1;//write
-
-
-
- //Time schedule settings
- let bits = [];
-
- //Byte 0 (LSB):
- //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
- bits.push(1);
- //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
- bits.push(0);
- bits.push(0);
- bits.push(0);
- if(nodeProfile.astro_clock == true)
- {
- //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
- bits.push(0);
-
- //Bity 6-7 - zatiaľ nepoužité
- bits.push(0);
- bits.push(0);
-
- params.byte4 = bitwise.byte.write(bits.reverse());
-
- //Byte 2 – nastavenie pre lux senzor:
- bits = [];
-
- //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if(nodeProfile.dusk_lux_sensor == true)//sumrak
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if(nodeProfile.dawn_lux_sensor == true)//usvit
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
- bits.push(0);//zatial neimplementovane
-
- //Bit 3 – 7 - nepoužité
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
-
- params.byte2 = bitwise.byte.write(bits.reverse());
- params.timestamp = timestamp;
- params.info = "Time schedule settings - turn on";
-
- tasksProfile.push(params);
-
- //zaver
- cmdCounter[node] = tasksProfile.length;
-
- //tasks.push(tasksProfile);
- tasks = tasks.concat(tasksProfile);
-
- }
-
- logger.debug("finished set profile for ", node);
-
-}
-
-
-function cleanUpRefFlowdataObj()
-{
- let now = new Date();
- let timestamp = now.getTime();
-
- //clear old refFlowdata references
- let keys = Object.keys(refFlowdataObj);
- for(let i = 0; i < keys.length; i++)
- {
- let timestampKey = keys[i];
-
- if((timestamp - timestampKey) > 60*1000 )
- {
- console.log("cleanUpRefFlowdataObj delete", timestampKey);
- delete refFlowdataObj[ timestampKey ];
- }
- }
-}
-
-
-function removeTask(obj)
-{
- let keys = Object.keys(obj);
- tasks = tasks.filter((task) => {
-
- let counter = 0;
- for(let i = 0; i < keys.length; i++)
- {
- let key = keys[i];
- if(task.hasOwnProperty(key) && obj.hasOwnProperty(key))
- {
- if(task[key] == obj[key]) counter++;
- }
- }
-
- if(counter == keys.length) return false;
- return true;
- });
-}
-
-
-
exports.install = function(instance) {
- let now = new Date();
- console.log("CMD Manager installed", now.toLocaleString("sk-SK"));
-
- const tbHandler = new DataToTbHandler(SEND_TO.tb);
- tbHandler.setSender(exports.title);
+ const SerialPort = require('serialport');
+ const { exec } = require('child_process');
+ const { crc16 } = require('easy-crc');
+ const { runSyncExec, writeData } = require('./helper/serialport_helper');
+ const { bytesToInt, longToByteArray, addZeroBefore } = require('./helper/utils');
+ const bitwise = require('bitwise');
- //FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name
- //const errorHandler = new ErrorToServiceHandler(instance, SEND_TO.infoSender);
- errorHandler.setProjectsId(FLOW.OMS_projects_id);
- //const errorHandler = new ErrorToServiceHandler(instance);
- //errorHandler.sendMessageToService("ahoj", 0);
+ var SunCalc = require('./helper/suncalc');
+ const DataToTbHandler = require('./helper/DataToTbHandler');
+ const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
+ const { sendNotification } = require('./helper/notification_reporter');
+ const process = require('process');
+ const { errLogger, logger, monitor } = require('./helper/logger');
- let sunCalcResult = calculateDuskDawn();
+ const dbNodes = TABLE("nodes");
+ const dbRelays = TABLE("relays");
- let reportDuskDawn = {
- dusk_time: sunCalcResult.dusk_time,
- dawn_time: sunCalcResult.dawn_time,
- dusk_time_reported: undefined,
- dawn_time_reported: undefined
- };
+ let GLOBALS;
+ let SETTINGS;
+ let rsPort;
+ let tbHandler;
+
+ // runTasks intervals
+ const SHORT_INTERVAL = 30;
+ const LONG_INTERVAL = 300;
+
+ //send data to following instances:
+ const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ http_response: 2,
+ dido_controller: 3,
+ infoSender: 4
+ }
+
+ const PRIORITY_TYPES = {
+ terminal: 0,
+ fw_detection: 1,//reserved only for FW detection - SETTINGS.masterNodeIsResponding
+ high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
+ relay_profile: 3,
+ node_broadcast: 4,
+ node_profile: 5,
+ node_cmd: 6
+ }
+
+ const TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION = 600000; // 10 minutes
+
+ //list of command calls to process. Processing in runTasks function
+ let tasks = [];
+
+ let interval = null;//timeout for procesing tasks
+ let customTasksInterval = null; // interval for reportEdgeDateTimeAndNumberOfLuminaires();
+ let setCorrectTime = null; // interval for setting a correct edgeTime
+
+ let refFlowdataObj = {};
+
+ //load from settings
+ let latitude = 48.70826502;//48.682255758;
+ let longitude = 17.28455203;//17.278910807;
+
+ const gmtOffset = 0;
+
+ //ak nie je nastaveny
+ //https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
+ //https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
+
+ //priorities for registers
+ let priorities = [];
+
+ let minutes = 1;
+ priorities["0"] = minutes;
+ priorities["1"] = minutes;
+
+ minutes = 5;
+ priorities["74"] = minutes;
+ priorities["75"] = minutes;
+ priorities["76"] = minutes;
+ priorities["77"] = minutes;
+ priorities["78"] = minutes;
+ priorities["79"] = minutes;
+ priorities["84"] = minutes;
+
+ minutes = 10;
+ priorities["87"] = minutes;
+ priorities["6"] = minutes;
+ priorities["7"] = minutes;
+ priorities["80"] = minutes;
+ priorities["8"] = minutes;
+ priorities["3"] = minutes;
+ priorities["89"] = minutes;
+
+ //prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
+ let listOfCommands = [0, 1, 3, 6, 7, 8, 74, 75, 76, 77, 78, 79, 80, 84, 87, 89];
+
+ const errorHandler = new ErrorToServiceHandler();
+
+ let rotary_switch_state;
+ let lux_sensor;
+ let state_of_breaker = {};//key is line, value is On/Off
+ let disconnectedReport = {};//key is tbname, value true/false
+
+ let relaysData;
+ let nodesData;
+ let rvoTbName;
+
+ let sunCalcResult;
+ let reportDuskDawn;
+
+ //helper container for counting resolved group of commands (commands related to set profile)
+ let cmdCounter = {};//key is node, value is counter
+
+ //END OF VARIABLE SETTINGS
+ //--------------------------------
- process.on('uncaughtException', function (err) {
+ function main() {
+ GLOBALS = FLOW.GLOBALS;
+ SETTINGS = FLOW.GLOBALS.settings;
+ relaysData = GLOBALS.relaysData;
+ nodesData = GLOBALS.nodesData;
+ latitude = GLOBALS.settings.latitude;
+ longitude = GLOBALS.settings.longitude;
+ tbHandler = new DataToTbHandler(SEND_TO.tb);
+ tbHandler.setSender(exports.title);
+
+ //SETTINGS.project_id, name: SETTINGS.rvo_name;
+ //const errorHandler = new ErrorToServiceHandler(instance, SEND_TO.infoSender);
+ errorHandler.setProjectsId(SETTINGS.project_id);
+ //const errorHandler = new ErrorToServiceHandler(instance);
+ //errorHandler.sendMessageToService("ahoj", 0);
+
+ let now = new Date();
+ console.log("CMD Manager installed", now.toLocaleString("sk-SK"));
+
+ sunCalcResult = calculateDuskDawn();
+
+ reportDuskDawn = {
+ dusk_time: sunCalcResult.dusk_time,
+ dawn_time: sunCalcResult.dawn_time,
+ dusk_time_reported: undefined,
+ dawn_time_reported: undefined
+ };
+
+ handleRsPort();
+
+ //to ensure, edgeDateTime will be send to tb at full minute
+ customTasksInterval = setInterval(function() {
+ if (new Date().getSeconds() === 0) reportEdgeDateTimeAndNumberOfLuminaires();
+ }, 1000);
+
+ setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
+ setCorrectPlcTimeOnceADay();
+ }
+
+
+ function cmdCounterResolve(address) {
+ if (cmdCounter.hasOwnProperty(address)) {
+ cmdCounter[address] = cmdCounter[address] - 1;
+
+ let result = cmdCounter[address];
+ if (result == 0) delete cmdCounter[address];
+ return result;
+ }
+ return -1;
+ }
+
+
+ function getParams(priority) {
+ let params = {};
+
+ //core rpc values
+ params.address = 0;//if(recipient === 0) address = 0;
+ params.byte1 = 0;//msb, podla dokumentacie data3
+ params.byte2 = 0;//podla dokumentacie data2
+ params.byte3 = 0;//podla dokumentacie data1
+ params.byte4 = 0;//lsb, podla dokumentacie data0
+ params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
+ params.register = -1;//register number
+ params.rw = 0;//0: read, 1: write
+
+ //other values
+ //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles"
+ //params.tbname = tbname;
+ params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
+ params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
+ if (priority != undefined) {
+ params.timestamp = priority;
+ params.priority = priority;
+ }
+
+ params.addMinutesToTimestamp = 0;//repeat task if value is > 0,
+
+ //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
+ //params.info = "";
+ //params.debug = true; // will console.log params in writeData response
+
+ return params;
+ }
+
+
+ //nastav profil nodu
+ function processNodeProfile(node) {
+ if (rotary_switch_state != "Automatic") {
+ logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
+ return;
+ }
+
+ let nodeObj = nodesData[node];
+ let line = nodeObj.line;
+
+ if (relaysData[line].contactor == 0) {
+ logger.debug("line line is off", line, node);
+ return;
+ }
+
+ if (nodeObj.processed == 1) {
+ //logger.debug("node was already processed", node);
+ return;
+ }
+
+ let nodeProfile = nodeObj.profile;
+ logger.debug("processNodeProfile: start - set profile for ", node, nodeProfile);
+ if (nodeProfile) {
+
+ try {
+ nodeProfile = JSON.parse(nodeProfile);
+ } catch (error) {
+ logger.debug("Cmd_manager - Error parsing node profile", error);
+ }
+
+ }
+
+ logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
+
+ let timestamp = PRIORITY_TYPES.node_cmd;
+
+ removeTask({ type: "set_node_profile", address: node });
+
+ if (nodeProfile === "") {
+ //vypneme profil nodu, posleme cmd
+ //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
+ //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
+
+ logger.debug("turn off profile");
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'turn off/reset node profile';
+
+ cmdCounter[node] = 1;
+
+ tasks.push(params);
+ }
+ else {
+ let tasksProfile = [];
+
+ //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'turn off node profile';
+
+ tasksProfile.push(params);
+
+ timestamp++;
+
+ logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
+
+ //TS1 Time point a TS1 Time Point Levels
+ let register = 9;
+ for (let i = 0; i < nodeProfile.intervals.length; i++) {
+ let obj = nodeProfile.intervals[i];
+ //let timePoint = obj.time_point;
+ let dim_value = obj.value;
+
+
+ //Reg 9 až Reg 40
+
+ /*
+ Samotný profil sa zapisuje do max. 16 párov – časový bod a úroveň.
+ Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF (táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8).
+ Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13:00.
+ Časový bod má formát:
+ Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované
+ Register úrovne má rovnaký formát ako dimming register (Reg 1).
+ */
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //params.byte1 = 0;//msb, podla dokumentacie data3
+ //params.byte2 = 0;//podla dokumentacie data2
+ //params.byte3 = 0;//podla dokumentacie data1
+ //params.byte4 = 0;//lsb, podla dokumentacie data0
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ let start_time = obj.start_time;
+ let t = start_time.split(":");
+ //if(timePoint != undefined) t = timePoint.split(":");
+ //else t = [0,0];
+
+ logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = parseInt(t[0]);//hh
+ params.byte2 = parseInt(t[1]);//mm
+ params.byte3 = 0;//ss
+ params.byte4 = 0;//
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;//ss
+ params.byte4 = parseInt(dim_value) + 128;//
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point Levels ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+ }
+
+ //Threshold lux level for DUSK/DAWN
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //params.byte1 = 0;//msb, podla dokumentacie data3
+ //params.byte2 = 0;//podla dokumentacie data2
+ //params.byte3 = 0;//podla dokumentacie data1
+ //params.byte4 = 0;//lsb, podla dokumentacie data0
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+ //Time schedule settings na koniec
+ //if(nodeProfile.dusk_lux_sensor || nodeProfile.dawn_lux_sensor)
+ {
+
+ logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 96;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "Threshold lux level for DUSK/DAWN";
+
+ if (nodeProfile.dusk_lux_sensor) {
+ let v = nodeProfile.dusk_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if (nodeProfile.dawn_lux_sensor) {
+ let v = nodeProfile.dawn_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //DUSK/DAWN max. adjust period
+ {
+
+ logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 97;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "DUSK/DAWN max. adjust period";
+
+ if (nodeProfile.astro_clock) {
+ let v = nodeProfile.dusk_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if (nodeProfile.astro_clock) {
+ let v = nodeProfile.dawn_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //Static offset
+ {
+
+ //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
+ //Bity 0 – 6: hodnota v minútach
+ //Bit 7: znamienko (1 – mínus)
+
+ logger.debug("processNodeProfile: Static offset", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 98;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "Static offset";
+
+ if (nodeProfile.astro_clock) {
+ let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
+ let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
+
+ if (dusk_astro_clock_offset < 0) {
+ params.byte3 = (dusk_astro_clock_offset * -1) + 128;
+ }
+ else {
+ params.byte3 = dusk_astro_clock_offset;
+ }
+
+ if (dawn_astro_clock_offset < 0) {
+ params.byte4 = (dawn_astro_clock_offset * -1) + 128;
+ }
+ else {
+ params.byte4 = dawn_astro_clock_offset;
+ }
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+ }
+
+ logger.debug("Time schedule settings - turn on", node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 8;
+ params.recipient = 1;
+ params.rw = 1;//write
+
+ //Time schedule settings
+ let bits = [];
+
+ //Byte 0 (LSB):
+ //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
+ bits.push(1);
+ //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ if (nodeProfile.astro_clock == true) {
+ //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
+ bits.push(0);
+
+ //Bity 6-7 - zatiaľ nepoužité
+ bits.push(0);
+ bits.push(0);
+
+ params.byte4 = bitwise.byte.write(bits.reverse());
+
+ //Byte 2 – nastavenie pre lux senzor:
+ bits = [];
+
+ //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if (nodeProfile.dusk_lux_sensor == true)//sumrak
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if (nodeProfile.dawn_lux_sensor == true)//usvit
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
+ bits.push(0);//zatial neimplementovane
+
+ //Bit 3 – 7 - nepoužité
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+
+ params.byte2 = bitwise.byte.write(bits.reverse());
+ params.timestamp = timestamp;
+ params.info = "Time schedule settings - turn on";
+
+ tasksProfile.push(params);
+
+ //zaver
+ cmdCounter[node] = tasksProfile.length;
+
+ //tasks.push(tasksProfile);
+ tasks = tasks.concat(tasksProfile);
+
+ }
+
+ logger.debug("finished set profile for ", node);
+
+ console.log("proces profile finished *********************")
+ }
+
+
+ function cleanUpRefFlowdataObj() {
+ let now = new Date();
+ let timestamp = now.getTime();
+
+ //clear old refFlowdata references
+ let keys = Object.keys(refFlowdataObj);
+ for (let i = 0; i < keys.length; i++) {
+ let timestampKey = keys[i];
+
+ if ((timestamp - timestampKey) > 60 * 1000) {
+ console.log("cleanUpRefFlowdataObj delete", timestampKey);
+ delete refFlowdataObj[timestampKey];
+ }
+ }
+ }
+
+
+ function removeTask(obj) {
+ let keys = Object.keys(obj);
+ tasks = tasks.filter((task) => {
+
+ let counter = 0;
+ for (let i = 0; i < keys.length; i++) {
+ let key = keys[i];
+ if (task.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
+ if (task[key] == obj[key]) counter++;
+ }
+ }
+
+ if (counter == keys.length) return false;
+ return true;
+ });
+ }
+
+
+ process.on('uncaughtException', function(err) {
//TODO send to service
-
+
errLogger.error('uncaughtException:', err.message)
errLogger.error(err.stack);
errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
//process.exit(1);
})
-
+
//te();//force error
- function processAllNodeProfilesOnLine(line)
- {
-
+ function processAllNodeProfilesOnLine(line) {
for (let k in nodesData) {
- //node:number|tbname:string|line:number|profile:string|processed:boolean
-
- if(line == nodesData[k].line)
- {
+ if (line == nodesData[k].line) {
let node = nodesData[k].node;
let processed = nodesData[k].processed;
- if(!processed)
- {
- processNodeProfile(node);
- }
- else
- {
- logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
- }
+ if (!processed) processNodeProfile(node);
+ //else logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
}
- }
- }
-
-
- async function loadRelaysData(line) {
-
- relaysData = await promisifyBuilder(dbRelays.find());
- relaysData = makeMapFromDbResult(relaysData, "line");
-
- for (const [key, value] of Object.entries(relaysData))
- {
- if(key == "0") continue;
- if(line != undefined)
- {
- //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
- if(line != value.line ) continue;
- }
-
- if(value.contactor == 1) processAllNodeProfilesOnLine(value.line);
}
-
-// console.log('.........', relaysData);
}
- function reportOnlineNodeStatus(line)
- {
+ function loadRelaysData(line) {
+ for (const [key, value] of Object.entries(relaysData)) {
+ if (key == "0") continue;
+ if (line != undefined) {
+ //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
+ if (line != value.line) continue;
+ }
+
+ if (value.contactor == 1) processAllNodeProfilesOnLine(value.line);
+ }
+ }
+
+
+ function reportOnlineNodeStatus(line) {
//broadcast cas, o 3 sek neskor - status, brightness
//Po zapnutí línie broadcastovo aktualizovať predtým čas.
logger.debug("--->reportOnlineNodeStatus for line", line);
//return;
-
+
//run broadcast //Actual time
addMinutesToTimestamp = 0;
let params = {};
- let recipient = 2;//2 broadcast, address = 0
- let address = 0;//0
- if(recipient === 2)
- {
- address = 0xffffffff;//Broadcast
- }
-
var d = new Date();
let hours = d.getHours();
let minutes = d.getMinutes();
let seconds = d.getSeconds();
- params.address = address;//broadcast
+ let time = d.getTime(); // time in ms
+
+ params.address = 0xffffffff;//Broadcast
params.byte1 = hours;//h
params.byte2 = minutes;//m
params.byte3 = seconds;//s
params.byte4 = 0;
- params.recipient = recipient;
+ params.recipient = 2;//2 broadcast, address = 0
params.register = 87;//Actual time
params.rw = 1;//write
- let timestampStart = PRIORITY_TYPES.node_broadcast;
-
//other values
params.type = "cmd";
- //params.tbname = tbname;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = addMinutesToTimestamp;
params.info = "run broadcast: Actual time";
tasks.push(params);
let sec = 3;
- setTimeout(function(){
+ setTimeout(function() {
//Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
for (let k in nodesData) {
-
+
//potrebujem nody k danej linii
- if(line == nodesData[k].line || line == undefined)
- {
+ if (line == nodesData[k].line || line == undefined) {
let tbname = nodesData[k].tbname;
let node = nodesData[k].node;
+ let status = "NOK";
+
+ // if status of node was "OK" before switching it off, we set the node's time_of_last_communication on time, it was switched on again and send OK status to tb.
+ if (nodesData[k].status) {
+ status = "OK";
+ nodesData[k].time_of_last_communication = time;
+ }
+
+ sendTelemetry({ status: status }, tbname, time);
//prud, vykon - current, input power pre liniu pre vsetky nody
-
+
//a pridame aj vyreportovanie dimmingu
{
let params = getParams(PRIORITY_TYPES.high_priority);
@@ -878,68 +781,43 @@ exports.install = function(instance) {
}
}
}
- },sec*1000);
+ }, sec * 1000);
}
- function reportOfflineNodeStatus(line)
- {
+ function reportOfflineNodeStatus(line) {
logger.debug("--->reportOfflineNodeStatus for line", line);
values = {};
values["dimming"] = 0;//brightness
values["power"] = 0;//výkon
values["current"] = 0;//prúd
- values["status"] = "OFFLINE";//prúd
-
- for (let k in nodesData) {
-
- //potrebujem nody k danej linii
- if(line == nodesData[k].line || line == undefined)
- {
- let tbname = nodesData[k].tbname;
+ values["status"] = "OFFLINE";
- //logger.debug("node:", tbname);
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
- }
- }
+ const date = Date.now();
- //report OFFLINE for line
- //relaysData[line].tbname;
+ // it happens, that some data did not get to tb after sending
+ // we setTimeout to make more time for db to process telemetry (eg 150 messages at once)
+ Object.keys(nodesData).forEach((node, index) => {
+
+ setTimeout(function() {
+
+ //potrebujem nody k danej linii
+ if (line == nodesData[node].line || line == undefined) {
+ let tbname = nodesData[node].tbname;
+ sendTelemetry(values, tbname, date)
+ }
+
+ }, (index + 1) * 1000);
+ })
- //values = {};
- //values["status"] = "OFFLINE";//prúd
}
- function turnOnLine(line, info)
- {
+ function turnLine(onOrOff, line, info) {
let obj = {
line: line,
- command: "turnOn",
- info: info
- };
-
- logger.debug("linia", line, obj);
- instance.send(SEND_TO.dido_controller, obj);
- }
-
- function turnOffLine(line, info)
- {
- let obj = {
- line: line,
- command: "turnOff",
+ command: onOrOff,
info: info
};
@@ -948,40 +826,40 @@ exports.install = function(instance) {
}
- function detectIfResponseIsValid(bytes)
- {
+
+ function detectIfResponseIsValid(bytes) {
//ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
let type = "RESPONSE";
- if(bytes[4] == 0) type = "RESPONSE";
- else if(bytes[4] == 1) type = "ERROR";
- else if(bytes[4] == 2) type = "EVENT";
+ if (bytes.length == 1) type = "BROADCAST"; // odpoved z rsPortu na broadcast command: ["broadcast"]
+ else if (bytes[4] == 0) type = "RESPONSE";
+ else if (bytes[4] == 1) type = "ERROR";
+ else if (bytes[4] == 2) type = "EVENT";
else type = "UNKNOWN";
-
+
+ let message = "OK";
+ let error = "";
+ if (type == "BROADCAST") return { message, type, error };
+
let crc = crc16('ARC', bytes.slice(0, 9));
let c1 = (crc >> 8) & 0xFF;
let c2 = crc & 0xFF;
-
- let message = "OK";
- let error = "";
- if(c1 != bytes[9])
- {
+
+ if (c1 != bytes[9]) {
//CRC_ERROR
message = "NOK";
error = "CRC_ERROR c1";
instance.send(SEND_TO.debug, "CRC_ERROR c1");
}
-
- if(c2 != bytes[10])
- {
+
+ if (c2 != bytes[10]) {
//CRC_ERROR
message = "NOK";
error = "CRC_ERROR c2";
instance.send(SEND_TO.debug, "CRC_ERROR c2");
}
-
+
//crc error
- if(type != "RESPONSE")
- {
+ if (type != "RESPONSE") {
instance.send(SEND_TO.debug, bytes);
instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]);
@@ -991,18 +869,18 @@ exports.install = function(instance) {
message = "NOK";
}
-
- return {message: message, type: type, error: error};
+
+ return { message, type, error };
}
//BUILD TASKS//
- function buildTasks(params)
- {
- //report FLOW.OMS_edge_fw_version as fw_version
+ function buildTasks(params) {
+ //report SETTINGS.edge_fw_version as fw_version
//report date as startdate
//return;
+ console.log("buidTAaasks start ****************", params);
monitor.info("buildTasks - params", params);
@@ -1012,14 +890,12 @@ exports.install = function(instance) {
let processBroadcast = true;
let processNodes = true;
- if(params == undefined)
- {
+ if (params == undefined) {
init = true;
tasks = [];
logger.debug("-->buildTasks clear tasks");
}
- else
- {
+ else {
processLineProfiles = false;
processBroadcast = false;
processNodes = false;
@@ -1028,23 +904,18 @@ exports.install = function(instance) {
processLine = params.line;
}
- //load profiles pre linie
- //relaysData[ record["line"] ]
-
+ //load profiles pre vsetky linie:
let now = new Date();
- if(processLineProfiles)
- {
+ if (processLineProfiles) {
//process line profiles
let keys = Object.keys(relaysData);
- for(let i = 0; i < keys.length; i++)
- {
+ for (let i = 0; i < keys.length; i++) {
let line = parseInt(keys[i]); //line is turned off by default
let profilestr = relaysData[line].profile;
- if(processLine != undefined)
- {
- if(processLine != line) continue;
+ if (processLine != undefined) {
+ if (processLine != line) continue;
}
try {
@@ -1052,15 +923,14 @@ exports.install = function(instance) {
/**
* we process line profiles: timepoints, astro clock, lux_sensor, offsets ...
*/
- if(profilestr === "") throw ("Profile is not defined");
+ if (profilestr === "") throw ("Profile is not defined");
let profile = JSON.parse(profilestr);
- if(Object.keys(profile).length === 0) throw ("Profile is empty");
+ if (Object.keys(profile).length === 0) throw ("Profile is empty");
monitor.info("buildTasks: profile for line", line);
monitor.info("profile:", profile);
- let time_points = profile.time_points;
- if(time_points == undefined) time_points = profile.intervals;
+ let time_points = profile.intervals;
// add name to regular profile timepoint and delete unused end_time key:
time_points.forEach(point => {
@@ -1070,17 +940,13 @@ exports.install = function(instance) {
//monitor.info("buildTasks: time_points", time_points);
- let currentValue = 0;
- if(time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
-
/**
* if astro_clock is true, we create timepoints, that switch on/off relays accordingly.
* we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn
* if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching
*/
- if(profile.astro_clock == true)
- {
+ if (profile.astro_clock == true) {
// if astro clock true, we remove all regular profile points
time_points = [];
@@ -1088,80 +954,66 @@ exports.install = function(instance) {
let sunCalcResult = calculateDuskDawn(new Date(), line);
// adding dusk dawn to timpoints
- if(profile.dawn_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dawn"], "value": 0, "name":"dawn"});
- if(profile.dusk_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dusk"], "value": 1, "name":"dusk"});
+ if (profile.dawn_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dawn"], "value": 0, "name": "dawn" });
+ if (profile.dusk_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dusk"], "value": 1, "name": "dusk" });
//if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit)
//force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
- if(profile.dawn_lux_sensor == true)
- {
- let [ahours, aminutes, aseconds] = sunCalcResult["dawn"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours));
- ad.setMinutes(parseInt(aminutes) + profile.dawn_lux_sensor_time_window);
- ad.setSeconds(0);
+ if (profile.dawn_lux_sensor == true) {
+ let [ahours, aminutes] = sunCalcResult["dawn"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dawn_lux_sensor_time_window, 0);
- let strDate = ad.getHours() + ":" + ad.getMinutes();
-
- time_points.push({"value": 0, "start_time": strDate, "name": "luxOff"});
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+ time_points.push({ "value": 0, "start_time": strDate, "name": "luxOff" });
}
- if(profile.dusk_lux_sensor == true)
- {
- let [ahours, aminutes, aseconds] = sunCalcResult["dusk"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours));
- ad.setMinutes(parseInt(aminutes) + profile.dusk_lux_sensor_time_window);
- ad.setSeconds(0);
+ if (profile.dusk_lux_sensor == true) {
+ let [ahours, aminutes] = sunCalcResult["dusk"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dusk_lux_sensor_time_window, 0);
- let strDate = ad.getHours() + ":" + ad.getMinutes();
-
- time_points.push({"value": 1, "start_time": strDate, "name": "luxOn"});
- //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+ time_points.push({ "value": 1, "start_time": strDate, "name": "luxOn" });
+ //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
}
}
//sort time_points
- time_points.sort(function (a, b) {
+ time_points.sort(function(a, b) {
+
+ let [ahours, aminutes] = a.start_time.split(':');
+ let [bhours, bminutes] = b.start_time.split(':');
- let [ahours, aminutes, aseconds] = a.start_time.split(':');
- let [bhours, bminutes, bseconds] = b.start_time.split(':');
-
let ad = new Date();
- ad.setHours( parseInt(ahours) );
- ad.setMinutes( parseInt(aminutes) );
- ad.setSeconds(0);
-
+ ad.setHours(parseInt(ahours), parseInt(aminutes), 0);
+
let bd = new Date();
- bd.setHours( parseInt(bhours) );
- bd.setMinutes( parseInt(bminutes) );
- ad.setSeconds(0);
-
+ bd.setHours(parseInt(bhours), parseInt(bminutes), 0);
+
return ad.getTime() - bd.getTime();
});
console.log("line timepoints ........", time_points);
- monitor.info("-->comming events turn on/off lines:");
- for(let t = 0; t < time_points.length; t++)
- {
-
- let start_time = new Date();
- let [hours, minutes, seconds] = time_points[t].start_time.split(':');
+ let currentValue = 0;
+ if (time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
- start_time.setHours( parseInt(hours) );
- start_time.setMinutes( parseInt(minutes) );
- start_time.setSeconds(0);
-
- //task is the past
- if(now.getTime() > start_time.getTime())
- {
+ monitor.info("-->comming events turn on/off lines:");
+ for (let t = 0; t < time_points.length; t++) {
+
+ let start_time = new Date();
+ let [hours, minutes] = time_points[t].start_time.split(':');
+ start_time.setHours(parseInt(hours), parseInt(minutes), 0);
+
+ //task is in the past
+ if (now.getTime() > start_time.getTime()) {
currentValue = time_points[t].value;
//timepoint is in past, we add 24 hours
start_time.setDate(start_time.getDate() + 1);
}
-
+
let params = getParams(PRIORITY_TYPES.relay_profile);
params.type = "relay";
params.line = parseInt(line);
@@ -1172,32 +1024,30 @@ exports.install = function(instance) {
params.addMinutesToTimestamp = 0;
// it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day
- if(time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24*60;
+ if (time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24 * 60;
//astro timepoints will be recalculated dynamically:
params.timePointName = time_points[t].name;
// if astro timepoint, we save time window:
- if(['luxOn', 'luxOff', 'dusk','dawn'].includes(params.timePointName))
- {
+ if (['luxOn', 'luxOff', 'dusk', 'dawn'].includes(params.timePointName)) {
params.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window;
params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window;
}
- if(params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
- else if(params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
+ if (params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
+ else if (params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
params.debug = true;
//turn on/off line
tasks.push(params);
- monitor.info(params.info, start_time);
-
+ monitor.info("TimePoint params: ", params.info, start_time);
}
monitor.info("-->time_points final", line, time_points);
- //ensure to turn on/off according to calculated value
+ //ensure to turn on/off according to calculated currentValue
let params = getParams(PRIORITY_TYPES.terminal);
params.type = "relay";
params.line = parseInt(line);
@@ -1212,14 +1062,13 @@ exports.install = function(instance) {
monitor.info("-->currentValue for relay", line, currentValue);
//turn on/off line
- if(params.value == 0) params.info = "turn off line on startup: " + line;
- else if(params.value == 1) params.info = "turn on line on startup: " + line;
+ if (params.value == 0) params.info = "turn off line on startup: " + line;
+ else if (params.value == 1) params.info = "turn on line on startup: " + line;
tasks.push(params);
} catch (error) {
- if(profilestr !=="" )
- {
+ if (profilestr !== "") {
//errLogger.error(profilestr, error);
errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error");
}
@@ -1233,59 +1082,50 @@ exports.install = function(instance) {
//PROCESS DEFAULT BROADCASTS
+ //Time of dusk, Time of dawn, Actual Time
- //RPC pre nody / broadcast
- //Time of dusk, Time of dawn
- //Actual Time
-
- if(processBroadcast)
- {
+ if (processBroadcast) {
let addMinutesToTimestamp = 5;
{
//run broadcast Time of dusk
addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk
-
+
let params = getParams(PRIORITY_TYPES.node_broadcast);
-
+
let sunCalcResult = calculateDuskDawn();
let dusk_hours = sunCalcResult["dusk_hours"];
let dusk_minutes = sunCalcResult["dusk_minutes"];
-
+
params.address = 0xffffffff;//broadcast
params.byte1 = dusk_hours;//h
params.byte2 = dusk_minutes;//m
params.byte3 = 0;//s
params.byte4 = 0;
- params.recipient = 2;//2 broadcast,
+ params.recipient = 2;//2 broadcast,
params.register = 6;//Time of dusk - Reg 6
params.rw = 1;//write
-
- let timestampStart = PRIORITY_TYPES.node_broadcast;
-
+
//other values
params.type = "cmd";
- //params.tbname = tbname;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = addMinutesToTimestamp;
params.info = "Broadcast-duskTime";
tasks.push(params);
-
}
-
+
{
-
+
//run broadcast Time of dawn
- // addMinutesToTimestamp = 60*5;
addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
-
+
let params = getParams(PRIORITY_TYPES.node_broadcast);
-
+
let sunCalcResult = calculateDuskDawn();
let dawn_hours = sunCalcResult["dawn_hours"];
let dawn_minutes = sunCalcResult["dawn_minutes"];
-
+
params.address = 0xffffffff;//broadcast
params.byte1 = dawn_hours;//h
params.byte2 = dawn_minutes;//m
@@ -1294,30 +1134,27 @@ exports.install = function(instance) {
params.recipient = 2; //2 broadcast
params.register = 7;//Time of dawn - Reg 6
params.rw = 1;//write
-
- let timestampStart = PRIORITY_TYPES.node_broadcast;
-
+
//other values
params.type = "cmd";
- //params.tbname = tbname;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = addMinutesToTimestamp;
params.info = "Broadcast-dawnTime";
-
+
tasks.push(params);
}
-
+
{
- //run broadcast //Actual time
+ //run broadcast Actual time
addMinutesToTimestamp = 5;
-
+
let params = getParams(PRIORITY_TYPES.node_broadcast);
-
+
var d = new Date();
let hours = d.getHours();
let minutes = d.getMinutes();
let seconds = d.getSeconds();
-
+
params.address = 0xffffffff;//broadcast
params.byte1 = hours;//h
params.byte2 = minutes;//m
@@ -1326,16 +1163,13 @@ exports.install = function(instance) {
params.recipient = 2; //2 broadcast
params.register = 87;//Actual time
params.rw = 1;//write
-
- let timestampStart = PRIORITY_TYPES.node_broadcast;
-
+
//other values
params.type = "cmd";
- //params.tbname = tbname;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = addMinutesToTimestamp;
params.info = "run broadcast: Actual time";
-
+
tasks.push(params);
}
@@ -1343,22 +1177,20 @@ exports.install = function(instance) {
//process nodes & tasks
//reportovanie pre platformu
- if(processNodes)
- {
+ if (processNodes) {
for (let k in nodesData) {
let address = parseInt(k);
let tbname = nodesData[k].tbname;
let register = 0;
-
+
//logger.debug("generated cmd - buildTasks for node:", address);
-
+
//listOfCommands - READ
- for(let i = 0; i < listOfCommands.length; i++)
- {
+ for (let i = 0; i < listOfCommands.length; i++) {
register = listOfCommands[i];
-
+
let params = getParams(PRIORITY_TYPES.node_cmd);
-
+
//core rpc values
params.address = address;
params.byte1 = 0;
@@ -1368,41 +1200,30 @@ exports.install = function(instance) {
params.recipient = 1;
params.register = register;
params.rw = 0;
-
+
let addMinutesToTimestamp = priorities[register];
-
+
let timestampStart = PRIORITY_TYPES.node_cmd; //run imediatelly in function runTasks
- if(addMinutesToTimestamp > 1)
- {
+ if (addMinutesToTimestamp > 1) {
timestampStart = timestampStart + addMinutesToTimestamp * 60000;
}
-
+
//other values
params.type = "cmd";
params.tbname = tbname;
params.timestamp = timestampStart;
params.addMinutesToTimestamp = addMinutesToTimestamp;
params.info = "generated cmd - buildTasks (node)";
-
- //monitor last node && last command
- /*
- if(register == listOfCommands[ listOfCommands.length - 1 ])
- {
- //if(k == 632) params.debug = true;
- if(k == 698) params.debug = true;
- }
- */
-
+
tasks.push(params);
-
+
}
}
}
-
//niektore ulohy sa vygeneruju iba 1x pri starte!!!
- if(!init) return;
+ if (!init) return;
//Priebežne (raz za cca 5 minút) je potrebné vyčítať z Master nodu verziu jeho FW.
@@ -1411,19 +1232,17 @@ exports.install = function(instance) {
//tak treba vyreportovať string "NOK".
{
let params = getParams(PRIORITY_TYPES.fw_detection);
- params.type = "cmd";
+ params.type = "cmd-master";
params.register = 4;
params.address = 0;
-
- let timestampStart = PRIORITY_TYPES.fw_detection;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = 5;
- params.tbname = FLOW.OMS_edgeName;
+ params.tbname = rvoTbName;
params.info = "Master node FW verzia";
//params.debug = true;
- //this will set FLOW.OMS_masterNodeIsResponding
-
+ //this will set SETTINGS.masterNodeIsResponding
+
tasks.push(params);
}
@@ -1431,42 +1250,10 @@ exports.install = function(instance) {
{
let params = getParams(PRIORITY_TYPES.fw_detection);
params.type = "process_profiles";
-
- let timestampStart = PRIORITY_TYPES.relay_profile;
- params.timestamp = timestampStart;
+ params.timestamp = Date.now() + 60000;
params.addMinutesToTimestamp = 60;//60 = every hour
params.info = "detekcia nespracovaných profilov linie a nodov";
//params.debug = true;
-
- tasks.push(params);
- }
-
- {
- //edge_date_time
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "edge_date_time";
-
- let timestampStart = PRIORITY_TYPES.node_cmd;
- params.timestamp = timestampStart;
- params.addMinutesToTimestamp = 1;
- params.tbname = FLOW.OMS_edgeName;
- params.info = "reportovanie aktuálneho času na LM - EDGE-Date Time";
- //logger.debug("BUILD Master node FW verzia");
- tasks.push(params);
- }
-
- {
- //edge_date_time
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "number_of_luminaires";
-
- let timestampStart = PRIORITY_TYPES.node_cmd + 1;
- params.timestamp = timestampStart;
- params.addMinutesToTimestamp = 1;
- params.tbname = FLOW.OMS_edgeName;
- params.info = "reportovanie number_of_luminaires";
tasks.push(params);
}
@@ -1496,15 +1283,13 @@ exports.install = function(instance) {
* dawn: usvit - lux je nad hranicou - vypnem
* dusk: sumrak - lux je pod hranicou - zapnem
*/
- function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value)
- {
+ function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) {
let now = new Date();
let currentTimestamp = now.getTime();
let keys = Object.keys(relaysData);
- for(let i = 0; i < keys.length; i++)
- {
+ for (let i = 0; i < keys.length; i++) {
let line = keys[i]; //line is turned off by default
let profilestr = relaysData[line].profile;
@@ -1513,38 +1298,31 @@ exports.install = function(instance) {
try {
let profile = JSON.parse(profilestr);
- if(Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
+ if (Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
- if(profile.astro_clock == true)
- {
+ if (profile.astro_clock == true) {
let sunCalcResult = calculateDuskDawn(now, line);
//usvit
- if(profile.dawn_lux_sensor == true)
- {
- let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
- let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60);
+ if (profile.dawn_lux_sensor == true) {
+ let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
+ let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60);
- if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
- {
- if(lux_sensor_value > profile.dawn_lux_sensor_value)
- {
- if(contactor) turnOffLine(line, "Profile: dawn - turnOff line according to lux sensor");
+ if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
+ if (lux_sensor_value > profile.dawn_lux_sensor_value) {
+ if (contactor) turnLine("off", line, "Profile: dawn - turnOff line according to lux sensor");
}
}
}
//sumrak
- if(profile.dusk_lux_sensor == true)
- {
- let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60);
- let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60);
+ if (profile.dusk_lux_sensor == true) {
+ let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
+ let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
- if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
- {
- if(lux_sensor_value < profile.dusk_lux_sensor_value)
- {
- if(!contactor) turnOnLine(line, "Profile: dusk - turnOn line according to lux sensor");
+ if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
+ if (lux_sensor_value < profile.dusk_lux_sensor_value) {
+ if (!contactor) turnLine("on", line, "Profile: dusk - turnOn line according to lux sensor");
}
}
}
@@ -1552,36 +1330,64 @@ exports.install = function(instance) {
}
} catch (error) {
- if(profilestr !== "" ) monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
+ if (profilestr !== "") monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
}
}
}
-
- async function upateNodeStatus(node, status)
- {
+ /**
+ * function updates status and time_of_last_communication of node in the dbNodes
+ * it only updates if conditions are met
+ * it only updates time_of_last_communication of node, if the last written time was more than 10 minutes ago (600000 miliseconds)
+ * if newStatus of node is always receiving false, and it is already for more than SETTINGS.node_status_nok_time value, we update status to "NOK" in tb
+ * function returns true, if status of node needs to be updated in TB (newStatus attribute is false in this case).
+ */
+ function updateNodeStatus(node, newStatus) {
//MASTER
- if(node == 0) return;
+ if (node == 0) return;
let nodeObj = nodesData[node];
- if(nodeObj == undefined) return;
+ if (nodeObj == undefined) return;
- if(status)
- {
- cmdNOKNodeCounter[node] = 0;
+ let nodeCurrentStatus = nodeObj.status;
+ const now = Date.now();
+
+ let data = null;
+
+ if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication > now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) return;
+ else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication < now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) {
+ data = { time_of_last_communication: now };
+ nodeDbStatusModify(node, data);
+ return;
+ }
+ else if (newStatus == false && nodeCurrentStatus == false) return true;
+ else if (newStatus == false && nodeCurrentStatus == true) {
+ if (nodeObj.time_of_last_communication + SETTINGS.node_status_nok_time > now) return;
+ else {
+ data = { status: newStatus };
+ nodeDbStatusModify(node, data);
+ return true;
+ }
+ }
+ else if (newStatus == true && nodeCurrentStatus == false) {
+ data = { status: newStatus, time_of_last_communication: now };
+ nodeDbStatusModify(node, data);
+ return;
}
- else cmdNOKNodeCounter[node]++;
- if(nodeObj.status !== status)
- {
- await dbNodes.modify({ status: status }).where("node", node).make(function(builder) {
- builder.callback(function(err, response) {
- if(err == null) nodesData[node].status = status;
- });
+ }
+
+
+ function nodeDbStatusModify(node, data) {
+ dbNodes.modify(data).where("node", node).make(function(builder) {
+ builder.callback(function(err, response) {
+ if (!err) {
+ nodesData[node] = { ...nodesData[node], ...data };
+ }
});
- }
+ });
}
@@ -1592,15 +1398,12 @@ exports.install = function(instance) {
let currentTimestamp = Date.now();
//report dusk, dawn---------------------------------
- if(reportDuskDawn.dusk_time < currentTimestamp)
- {
+ if (reportDuskDawn.dusk_time < currentTimestamp) {
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
- if( (currentTimestamp - reportDuskDawn.dusk_time) < 60 * 1000)
- {
+ if ((currentTimestamp - reportDuskDawn.dusk_time) < 60 * 1000) {
//reportovali sme?
- if(reportDuskDawn.dusk_time_reported != sunCalcResult.dusk_time)
- {
- sendNotification("CMD Manager: calculated Time of dusk", FLOW.OMS_edgeName, "dusk_has_occured", {value: sunCalcResult["dusk"]}, "", SEND_TO.tb, instance);
+ if (reportDuskDawn.dusk_time_reported != sunCalcResult.dusk_time) {
+ sendNotification("CMD Manager: calculated Time of dusk", SETTINGS.rvoTbName, "dusk_has_occured", { value: sunCalcResult["dusk"] }, "", SEND_TO.tb, instance);
reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
}
}
@@ -1612,15 +1415,12 @@ exports.install = function(instance) {
reportDuskDawn.dusk_time = sunCalcResult.dusk_time;
}
- if(reportDuskDawn.dawn_time < currentTimestamp)
- {
+ if (reportDuskDawn.dawn_time < currentTimestamp) {
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
- if( (currentTimestamp - reportDuskDawn.dawn_time) < 60 * 1000)
- {
+ if ((currentTimestamp - reportDuskDawn.dawn_time) < 60 * 1000) {
//reportovali sme?
- if(reportDuskDawn.dawn_time_reported != sunCalcResult.dawn_time)
- {
- sendNotification("CMD Manager: calculated Time of dawn", FLOW.OMS_edgeName, "dawn_has_occured", {value: sunCalcResult["dawn"]}, "", SEND_TO.tb, instance);
+ if (reportDuskDawn.dawn_time_reported != sunCalcResult.dawn_time) {
+ sendNotification("CMD Manager: calculated Time of dawn", SETTINGS.rvoTbName, "dawn_has_occured", { value: sunCalcResult["dawn"] }, "", SEND_TO.tb, instance);
reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
}
}
@@ -1635,155 +1435,67 @@ exports.install = function(instance) {
//--------------------------------------------------------
//sort tasks based on timestamp
- tasks.sort(function (a, b) {
- if(a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp)
- {
+ tasks.sort(function(a, b) {
+ if (a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp) {
return a.priority - b.priority;
}
return a.timestamp - b.timestamp;
});
- if(tasks.length == 0 )
- {
+ if (tasks.length == 0) {
instance.send(SEND_TO.debug, "no tasks created");
interval = setInterval(runTasks, LONG_INTERVAL);
return;
}
- if(!rsPort.isOpen)
- {
+ if (!rsPort.isOpen) {
instance.send(SEND_TO.debug, "!rsPort.isOpen");
//await rsPort.open();
+ console.log("Cmd_manager - !rsPort.isOpen");
}
let currentTask = tasks[0];
- if(currentTask.debug)
- {
+ if (currentTask.debug) {
//logger.debug("--->task to process", currentTask);
}
- if(currentTask.timestamp <= currentTimestamp)
- {
- let params = {...tasks[0]};
+ if (currentTask.timestamp <= currentTimestamp) {
+ let params = { ...tasks[0] };
//allow terminal commands
- if(FLOW.OMS_maintenance_mode && params.type !== "cmd-terminal")
- {
+ if (SETTINGS.maintenance_mode && params.type !== "cmd-terminal") {
interval = setInterval(runTasks, LONG_INTERVAL);
return;
}
let type = params.type;
let tbname = params.tbname;
- let nodeKey = params.address;
+ let nodeAddress = params.address;
let line = null;
//rpc related
- if(nodesData[nodeKey] !== undefined) line = nodesData[nodeKey].line;
- if(params.line !== undefined) line = params.line;
+ if (nodesData[nodeAddress] !== undefined) line = nodesData[nodeAddress].line;
+ if (params.line !== undefined) line = params.line;
let repeatTask = false;
- if(params.addMinutesToTimestamp > 0 || params.timePointName) repeatTask = true;
+ if (params.addMinutesToTimestamp > 0 || params.timePointName) repeatTask = true;
- if(repeatTask)
- {
- if(type === "cmd")
- {
+ if (repeatTask) {
+ if (type === "cmd" || type === "cmd-master") {
//set next start time automatically
tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
}
}
- else
- {
+ else {
tasks.shift();
}
- //custom tasks
- if(type == "number_of_luminaires")
- {
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
-
- //treba reportovat node status
- {
- //number_of_luminaires
- //number_of_ok_luminaires
- //number_of_nok_luminaires
-
- let keys = Object.keys(nodesData);
-
- let number_of_luminaires = keys.length;
- let number_of_ok_luminaires = 0;
- let number_of_nok_luminaires = 0;
-
- for(let i = 0; i < keys.length; i++)
- {
- let key = keys[i];
- let nodeObj = nodesData[key];
- if(nodeObj.tbname == undefined) continue;
-
- if(nodeObj.status) number_of_ok_luminaires++;
- else number_of_nok_luminaires++;
- }
-
- let values = {
- number_of_luminaires: number_of_luminaires,
- number_of_ok_luminaires: number_of_ok_luminaires,
- number_of_nok_luminaires: number_of_nok_luminaires
- };
-
- let dataToTb = {
- [FLOW.OMS_edgeName]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
-
- interval = setInterval(runTasks, SHORT_INTERVAL);
-
- return;
- }
- }
-
-
//kontrola nespracovanych profilov nodov
- if(type == "process_profiles")
- {
+ if (type == "process_profiles") {
tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
- //select nespracovane nody
- //node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean
-
- //buildTasks({processLineProfiles: true, line: line});
-
- /*
- let keys = Object.keys(nodesData);
- for(let i = 0; i < keys.length; i++)
- {
- let node = keys[i];
- let line = node.line;
-
- if(node.processed) continue;
-
- if(relaysData[line] != undefined)
- {
- let relayStatus = relaysData[line].contactor;
- if(relayStatus == 1)
- {
- //linia je zapnuta
- //await loadRelaysData(flowdata.data.line);
- }
- }
-
- }
- */
-
//vsetky linie kt. su zapnute, a spracuju sa nespracovane profily nodov
loadRelaysData();
@@ -1791,31 +1503,8 @@ exports.install = function(instance) {
return;
}
- if(type == "edge_date_time")
- {
- const ts = Date.now();
-
- let values = {"edge_date_time": ts};
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": ts,
- "values": values
- }
- ]
- }
-
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
-
- instance.send(SEND_TO.tb, dataToTb);
- interval = setInterval(runTasks, SHORT_INTERVAL);
- return;
- }
-
//relay
- if(type == "relay")
- {
+ if (type == "relay") {
const timePointName = params.timePointName;
const value = params.value;
@@ -1824,45 +1513,31 @@ exports.install = function(instance) {
date.setDate(date.getDate() + 1);//next day
let sunCalcResult;
- sunCalcResult = calculateDuskDawn(date, params.line);
+ if (timePointName) sunCalcResult = calculateDuskDawn(date, params.line);
- if(timePointName == "dawn")
- {
+ if (timePointName == "dawn") {
tasks[0].timestamp = sunCalcResult.dawn_time;
}
- else if(timePointName == "dusk")
- {
+ else if (timePointName == "dusk") {
tasks[0].timestamp = sunCalcResult.dusk_time;
}
- else if(timePointName == "luxOn")
- {
+ else if (timePointName == "luxOn") {
tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000;
}
- else if(timePointName == "luxOff")
- {
+ else if (timePointName == "luxOff") {
tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000;
}
- else if(timePointName == "profileTimepoint")
- {
+ else if (timePointName == "profileTimepoint") {
tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
}
let info = "aplikovany bod profilu";
let message = "";
- if(value == 1)
- {
- turnOnLine(params.line, info);
- message = "on";
- }
- else if(value == 0)
- {
- turnOffLine(params.line, info);
- message = "off";
- }
+ value == 1 ? message = "on" : message = "off";
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", SEND_TO.tb, instance, null );
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", SEND_TO.tb, instance );
+ turnLine(message, params.line, info);
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "switching_profile_point_applied_to_line", { line: params.line, value: message }, "", SEND_TO.tb, instance);
interval = setInterval(runTasks, SHORT_INTERVAL);
return;
}
@@ -1872,37 +1547,23 @@ exports.install = function(instance) {
//if(rotary_switch_state == "Off") disconnected = true;
//state_of_breaker[line] - alebo istic linie
- if(state_of_breaker.hasOwnProperty(line))
- {
+ if (state_of_breaker.hasOwnProperty(line)) {
//if(state_of_breaker[line] == "Off") disconnected = true;
}
//toto sa reportuje po prijati dat z dido_controlera
- if(disconnected)
- {
-
- let values = {"status": "OFFLINE"};
+ if (disconnected) {
+ let values = { "status": "OFFLINE" };
logger.debug("disconnected", values);
logger.debug("rotary_switch_state", rotary_switch_state);
logger.debug("state_of_breaker", state_of_breaker[line]);
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
//report only once!
- if(!disconnectedReport.hasOwnProperty(tbname)) disconnectedReport[tbname] = false;
+ if (!disconnectedReport.hasOwnProperty(tbname)) disconnectedReport[tbname] = false;
- if(!disconnectedReport[tbname])
- {
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
+ if (!disconnectedReport[tbname]) {
+ sendTelemetry(values, tbname)
}
interval = setInterval(runTasks, SHORT_INTERVAL);
@@ -1912,67 +1573,51 @@ exports.install = function(instance) {
disconnectedReport[tbname] = false;
+ const register = params.register;
+
//high_priority
- if(!FLOW.OMS_masterNodeIsResponding)
- {
+ if (!SETTINGS.masterNodeIsResponding) {
//ak neodpoveda, nebudeme vykonavat ziadne commands, okrem cmd-terminal, a fw version
errorHandler.sendMessageToService("Master node is not responding");
let stop = true;
- if(params.type == "cmd-terminal") stop = false;
//fw version - register == 4
- if(params.type == "cmd" && params.register == 4 && params.address == 0) stop = false;
-
- if(stop)
- {
+ if (type == "cmd-terminal" || register == 4) stop = false;
+ if (stop) {
interval = setInterval(runTasks, LONG_INTERVAL);
return;
}
}
let relayStatus = 1;
- if(relaysData[line] != undefined)
- {
+ if (relaysData[line] != undefined) {
relayStatus = relaysData[line].contactor;
}
- if(line == 0) relayStatus = 0;
- if(params.type == "cmd-terminal") relayStatus = 1;
+
+ if (line == 0) relayStatus = 0;
+ if (type == "cmd-terminal") relayStatus = 1;
//check if rotary_switch_state == "Off"
-
- if(relayStatus == 0)
- {
+ if (relayStatus == 0) {
//console.log("------------------------------------relayStatus", relayStatus, line);
- let values = {"status": "OFFLINE"};
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
+ let values = { "status": "OFFLINE" };
+
+ sendTelemetry(values, tbname)
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
-
interval = setInterval(runTasks, SHORT_INTERVAL);
return;
}
- if(!rsPort.isOpen)
- {
+ if (!rsPort.isOpen) {
interval = setInterval(runTasks, LONG_INTERVAL);
return;
}
-
+
//RE-CALCULATE VALUES
//set actual time for broadcast
- if(params.register == 87 && params.recipient === 2)
- {
+ if (register == 87 && params.recipient === 2) {
var d = new Date();
let hours = d.getHours();
let minutes = d.getMinutes();
@@ -1986,15 +1631,13 @@ exports.install = function(instance) {
//SET DUSK/DAWN FOR BROADCAST
//Time of dusk
- if(params.register == 6 && params.recipient === 2)
- {
+ if (register == 6 && params.recipient === 2) {
- if(params.type != "cmd-terminal")
- {
+ if (type != "cmd-terminal") {
let sunCalcResult = calculateDuskDawn();
let dusk_hours = sunCalcResult["dusk_hours"];
let dusk_minutes = sunCalcResult["dusk_minutes"];
-
+
params.byte1 = dusk_hours;//h
params.byte2 = dusk_minutes;//m
params.byte3 = 0;//s
@@ -2002,19 +1645,16 @@ exports.install = function(instance) {
//TODO astrohodiny
let dusk = "Time of dusk: " + sunCalcResult["dusk"];
- //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", SEND_TO.tb, instance, null );
}
}
//Time of dawn
- if(params.register == 7 && params.recipient === 2)
- {
- if(params.type != "cmd-terminal")
- {
+ if (register == 7 && params.recipient === 2) {
+ if (type != "cmd-terminal") {
let sunCalcResult = calculateDuskDawn();
let dawn_hours = sunCalcResult["dawn_hours"];
let dawn_minutes = sunCalcResult["dawn_minutes"];
-
+
params.byte1 = dawn_hours;//h
params.byte2 = dawn_minutes;//m
params.byte3 = 0;//s
@@ -2022,565 +1662,414 @@ exports.install = function(instance) {
//TODO astrohodiny
let dawn = "Time of dawn: " + sunCalcResult["dawn"];
- //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", SEND_TO.tb, instance, null );
}
-
+
}
//-----------------------
-
- let register = params.register;
- instance.send(SEND_TO.debug, "address: " + params.address + " register:" + params.register + "type: " + params.type);
+ instance.send(SEND_TO.debug, "address: " + nodeAddress + " register:" + register + "type: " + type);
var startTime, endTime;
startTime = new Date();
- let resp = com_generic(params.address, params.recipient, params.rw, params.register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
- let readBytes = 11;
- let timeout = 5000;
+ let saveToTb = true;
+ if (!tbname) saveToTb = false;
+ let itIsNodeCommand = listOfCommands.includes(register); //reading data from node (voltage, current, dimming, status)
- await writeData(rsPort, resp, readBytes, timeout).then(function (data) {
+ let resp = com_generic(nodeAddress, params.recipient, params.rw, register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
+ let readBytes = 11;
+ let timeout = 4000;
+
+ // await keyword is important, otherwise incorrect data is returned!
+ await writeData(rsPort, resp, readBytes, timeout).then(function(data) {
endTime = new Date();
var timeDiff = endTime - startTime;
- //--1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data
- //let bytes = data.slice(0);
- let bytes = data;
- let dataBytes = data.slice(5,9);
-
- let result = detectIfResponseIsValid(bytes);
-
- let message = result.message;
- let type = result.type;
- let error = result.error;
+ //data je array z 11 bytov: 1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data a 2 byty CRC
+ let dataBytes = data.slice(5, 9);
+ let result = detectIfResponseIsValid(data);
//ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
+ let message = result.message; // OK, NOK
+ let message_type = result.type;
+ let error = result.error;
- if(params.debug != "generated cmd")
- {
- //debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug, params);
+ if (params.debug != "generated cmd") {
+ //debug("writeData: done " + message_type + " duration: " + timeDiff + " message_type: " + params.debug, params);
}
- if(params.hasOwnProperty("debug"))
- {
- if(params.debug)
- {
- console.log("detected response:", result);
+ // if(params.hasOwnProperty("debug"))
+ // {
+ // if(params.debug)
+ // {
+ // console.log("detected response:", result);
- logger.debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug, params, result);
- }
- }
+ // logger.debug("writeData: done " + message_typetype + " duration: " + timeDiff + " type: " + params.debug, params, result);
+ // }
+ // }
- //debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug);
- //debug("writeData done", type, "duration", timeDiff, "type", params.debug, result);
+ //debug("writeData: done " + message_type + " duration: " + timeDiff + " message_type: " + params.debug);
+ //debug("writeData done", message_type, "duration", timeDiff, "message_type", params.debug, result);
- let tbname = params.tbname;
-
- let saveToTb = true;
- if(tbname == null || tbname == undefined || tbname == "") saveToTb = false;
- //--
+ let values = {};
//CMD FINISHED
- if(message == "OK")
- {
+ if (message == "OK") {
- upateNodeStatus(params.address, true);
+ updateNodeStatus(nodeAddress, true);
//write
- if(params.type == "set_node_profile")
- {
- let result = cmdCounterResolve(params.address);
- if(result == 0)
- {
-
- dbNodes.modify({ processed: true }).where("node", params.address).make(function(builder) {
-
+ if (type == "set_node_profile") {
+ let result = cmdCounterResolve(nodeAddress);
+ if (result == 0) {
+ dbNodes.modify({ processed: true }).where("node", nodeAddress).make(function(builder) {
builder.callback(function(err, response) {
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "dimming_profile_was_successfully_received_by_node", {node: params.address}, "", SEND_TO.tb, instance );
-
- logger.debug( "--> profil úspešne odoslaný na node č. " + params.address);
- nodesData[params.address].processed = true;
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: nodeAddress }, "", SEND_TO.tb, instance);
- });
+ logger.debug("--> profil úspešne odoslaný na node č. " + nodeAddress);
+ nodesData[nodeAddress].processed = true;
});
+ });
}
}
//parse read response
- let values = {};
- if(params.rw == 0) {
- values = processResponse(register, dataBytes);//read
- }
- if(params.rw == 1)
- { //write command
- //set command dimming
- if(params.register == 1) values = {"comm_status": message};
+ if (params.rw == 0) {
+ values = processResponse(register, dataBytes); //read
}
- if(params.register == 0) values["status"] = message;
+ if (itIsNodeCommand) {
+ values.comm_status = "OK";
+ values.status = "OK";
+ }
- //fw version - register == 4
- if(params.register == 4) values["edge_fw_version"] = FLOW.OMS_edge_fw_version;
-
- if(params.address == 0)
- {
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", SEND_TO.tb, instance, "rvo_status" );
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" );
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" );
- FLOW.OMS_masterNodeIsResponding = true;
+ //master node
+ if (nodeAddress == 0) {
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status");
+ SETTINGS.masterNodeIsResponding = true;
+ if (register == 4) values["edge_fw_version"] = SETTINGS.edge_fw_version;
}
//odoslanie príkazu z terminálu - dáta
- if(params.type == "cmd-terminal")
- {
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.DEBUG, "odoslanie príkazu z terminálu", params, SEND_TO.tb, instance, null );
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "command_was_sent_from_terminal_interface", {}, params, SEND_TO.tb, instance );
+ if (type == "cmd-terminal") {
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "command_was_sent_from_terminal_interface", {}, params, SEND_TO.tb, instance);
}
- if(params.debug)
- {
- logger.debug("saveToTb", saveToTb, tbname, values);
+ if (params.debug) {
+ //logger.debug("saveToTb", saveToTb, tbname, values);
}
- if(saveToTb)
- {
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
-
+ if (saveToTb) {
+ sendTelemetry(values, tbname)
}
- else
- {
-
- if(params.type == "cmd-terminal")
- {
- if(params.refFlowdataKey != undefined)
- {
-
- logger.debug("cmd-terminal SUCCESS");
- logger.debug(currentTask);
-
- //make http response
- let responseObj = {};
- responseObj["type"] = "SUCESS";
- responseObj["bytes"] = data;
-
- //params.refFlowdata.data = responseObj;
- //instance.send(SEND_TO.http_response, params.refFlowdata);
-
- let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
- refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, refFlowdata);
-
- }
- else
- {
- console.log("params.refFlowdataKey is undefined", params);
- }
+ else {
+ if (type == "cmd-terminal") {
+ terminalCommandResponse(params, "SUCCESS", data);
}
-
}
}
- else
- {
+ else {
- upateNodeStatus(params.address, false);
+ terminalCommandResponse(params, "ERROR", data)
+ handleNokResponseOnRsPort("handleNOK else block", params, itIsNodeCommand, saveToTb);
- if(params.refFlowdataKey != undefined)
- {
-
- logger.debug("cmd-terminal FAILED");
- logger.debug(currentTask);
-
- //make http response
- let responseObj = {};
- responseObj["type"] = "ERROR";
- responseObj["bytes"] = data;
-
- //params.refFlowdata.data = responseObj;
- //instance.send(SEND_TO.http_response, params.refFlowdata);
-
- let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
- if(refFlowdata !== undefined)
- {
- refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, refFlowdata);
- }
-
-
- }
-
- /*
- if(params.type == "cmd-terminal")
- {
- if(params.refFlowdata != undefined)
- {
-
- logger.debug("cmd-terminal FAILED");
- logger.debug(currentTask);
-
- //make http response
- let responseObj = {};
- responseObj["type"] = "ERROR";
- responseObj["bytes"] = data;
-
- params.refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, params.refFlowdata);
-
- }
- }
- */
-
- if(params.address == 0)
- {
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status");
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
- logger.debug("master_node_is_not_responding", params);
- FLOW.OMS_masterNodeIsResponding = false;
- }
-
- if(params.type == "set_node_profile")
- {
- delete cmdCounter[params.address];
- let tbname = nodesData[ params.address ].tbname;
-
- logger.debug( "profil nebol úspešne odoslaný na node č. ", params, result, resp);
-
- //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "profil nebol úspešne odoslaný na node č. " + params.address, "", SEND_TO.tb, instance, null );
- sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance );
- }
-
- //is it node?
- if(nodesData.hasOwnProperty(params.address))
- {
- if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
- }
-
- //Master node version
- //if(params.register == 4 && saveToTb)
- if(saveToTb)
- {
- let values = {
- "status": "NOK"
- };
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
- }
-
- //instance.send(SEND_TO.debug, result);
-
- if(params.hasOwnProperty("debug"))
- {
- if(params.debug)
- {
- logger.debug("writeData err: ", error, result, params);
+ if (params.hasOwnProperty("debug")) {
+ if (params.debug) {
+ //logger.debug("writeData err: ", error, result, params);
+ logger.debug("writeData err: ", tbname, nodeAddress, register, values);
}
}
//logger.debug(error, result, params);
}
-
- }).catch(function (reason) {
+ }).catch(function(reason) {
console.log("writeData catch exception", reason);
- logger.debug(currentTask);
+ instance.send(SEND_TO.debug, reason);
- if(params.refFlowdataKey != undefined)
- {
+ terminalCommandResponse(params, "FAILURE", null, reason);
+ handleNokResponseOnRsPort("handleNOK catch block", params, itIsNodeCommand, saveToTb);
- logger.debug("catch: cmd-terminal FAILED");
- logger.debug(currentTask);
-
- //make http response
- let responseObj = {};
- responseObj["type"] = "ERROR";//
- responseObj["message"] = "ERROR WRITE FAILED: " + reason;//
-
- //params.refFlowdata.data = responseObj;
- //instance.send(SEND_TO.http_response, params.refFlowdata);
-
- let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
- if(refFlowdata !== undefined)
- {
- refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, refFlowdata);
- }
-
-
- }
- /*
- if(params.type == "cmd-terminal")
- {
- if(params.refFlowdata != undefined)
- {
-
- logger.debug("cmd-terminal FAILED");
- logger.debug(currentTask);
-
- //make http response
- let responseObj = {};
- responseObj["type"] = "ERROR WRITE FAILED: " + reason;
- //responseObj["bytes"] = data;
-
- params.refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, params.refFlowdata);
-
- //refFlowdata = undefined;
- }
- }
- */
-
- if(params.hasOwnProperty("debug"))
- {
- if(params.debug)
- {
+ if (params.hasOwnProperty("debug")) {
+ if (params.debug) {
logger.debug("-->WRITE FAILED: " + reason, params.debug, params);
}
}
- upateNodeStatus(params.address, false);
-
- let tbname = params.tbname;
-
- let saveToTb = true;
- if(tbname == null || tbname == undefined || tbname == "") saveToTb = false;
-
- if(params.address == 0)
- {
- //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status");
- sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
- logger.debug("master_node_is_not_responding", params);
-
- FLOW.OMS_masterNodeIsResponding = false;
- }
-
- if(params.type == "set_node_profile")
- {
- delete cmdCounter[params.address];
- let tbname = nodesData[ params.address ].tbname;
-
- logger.debug( "profil nebol úspešne odoslaný na node č. ", params, resp);
-
- //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "odosielanie profilu na node č. " + params.address + " zlyhalo", "", SEND_TO.tb, instance, null );
- sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance );
- }
-
- //is it node?
- if(nodesData.hasOwnProperty(params.address))
- {
- if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
- }
-
- //Master node version
- if(params.register == 4 && saveToTb)
- {
- let values = {
- "status": "NOK",
- "master_node_version": "NOK"
- };
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
-
- FLOW.OMS_masterNodeIsResponding = false;
- }
- //treba?
- /*
- else if(saveToTb)
- {
- let values = {
- "comm_status": "no_comm"
- };
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- instance.send(SEND_TO.tb, dataToTb);
- }
- */
-
- instance.send(SEND_TO.debug, reason);
});
-
+
}
- else
- {
- if(currentTask.debug)
- {
- //currentTask.timestamp <= currentTimestamp
- logger.debug("currentTask is not processed - task is in the future", currentTask);
- }
+ else {
+ // if(currentTask.debug)
+ // {
+ // //currentTask.timestamp <= currentTimestamp
+ // logger.debug("currentTask is not processed - task is in the future", currentTask);
+ // }
interval = setInterval(runTasks, LONG_INTERVAL);
return;
- }
+ }
//console.log("----->runTasks - setInterval", new Date());
interval = setInterval(runTasks, SHORT_INTERVAL);
- }
-
+ }
- //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
- // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
- // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
- if(FLOW.OMS_serial_port == "" || FLOW.OMS_serial_port == undefined || FLOW.OMS_serial_port.length === 1) FLOW.OMS_serial_port = "ttymxc4";
- const rsPort = new SerialPort(`/dev/${FLOW.OMS_serial_port}`, { autoOpen: false });
- //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
- //rsPort.setMaxListeners(0);
+ function handleNokResponseOnRsPort(message, params, itIsNodeCommand, saveToTb) {
- rsPort.on('open', async function() {
+ let node = params.address;
+ let register = params.register;
+ let type = params.type;
+ let tbName = params.tbname;
+ if (!tbName) return;
- logger.debug("CMD manager - rsPort opened sucess");
+ let values = {};
- loadRelaysData();
+ // console.log(message);
+ let updateStatus = updateNodeStatus(node, false);
- await runSyncExec(`stty -F /dev/${FLOW.OMS_serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function (status) {
- instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status);
+ //master node
+ if (node == 0) {
+ sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
+ logger.debug("master_node_is_not_responding", params);
+ SETTINGS.masterNodeIsResponding = false;
- logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status);
+ if (register == 4) values["master_node_version"] = "NOK";
+ }
- //APP START
- let dataToInfoSender = {id: FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name};
- dataToInfoSender.fw_version = FLOW.OMS_edge_fw_version;
- dataToInfoSender.startdate = new Date().toISOString().slice(0, 19).replace('T', ' ');
- dataToInfoSender.__force__ = true;
-
- instance.send(SEND_TO.infoSender, dataToInfoSender);
+ if (type == "set_node_profile") {
+ delete cmdCounter[node];
+ logger.debug("profil nebol úspešne odoslaný na node č. ", params);
+ sendNotification("CMD Manager: process cmd", tbName, "configuration_of_dimming_profile_to_node_failed", { node: node }, "", SEND_TO.tb, instance);
+ }
- logger.debug(0, "---------------------------->START message send to service", dataToInfoSender);
+ if (itIsNodeCommand) {
+ values.comm_status = "NOK";
+ }
- }).catch(function (reason) {
- instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason);
+ if (updateStatus) {
+ values.status = "NOK";
+ }
+
+ // console.log("------",node, register, type, itIsNodeCommand, updateStatus, saveToTb, values);
+ if (saveToTb && Object.keys(values).length > 0) {
+ sendTelemetry(values, tbName)
+ }
+
+ }
+
+
+ /**
+ * function handles requests from terminal
+ * responseType can be "SUCCESS", "ERROR" or "FAILURE", depending on rsPort data.
+ * FAILURE means, that we got into catch block of writeData function.
+ */
+ function terminalCommandResponse(params, responseType, data = null, reason = "") { //success, error, failure
+
+ if (params.refFlowdataKey == undefined) {
+ //console.log("params.refFlowdataKey is undefined", params);
+ return;
+ }
+ else {
+ console.log("params.refFlowdataKey: ", params);
+ }
+
+ let message = null;
+ let type = null;
+
+ switch (responseType) {
+ case "SUCCESS":
+ message = "cmd-terminal SUCCESS";
+ type = "SUCCESS";
+ break;
+ case "ERROR":
+ message = "cmd-terminal FAILED";
+ type = "ERROR";
+ break;
+ case "FAILURE":
+ message = "ERROR WRITE FAILED: " + reason;
+ type = "ERROR";
+ break;
+ default:
+ type = undefined;
+ }
+
+ logger.debug(message);
+ logger.debug(params);
+
+ //make http response
+ let responseObj = {}
+ responseObj["type"] = type;
+
+ if (responseType == "FAILURE") responseObj["message"] = "ERROR WRITE FAILED: " + reason;
+ else responseObj["bytes"] = data;
+
+ let refFlowdata = refFlowdataObj[params.refFlowdataKey]; //holds reference to httprequest flowdata
+ if (refFlowdata) {
+ refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, refFlowdata);
+ }
+ }
+
+
+ /**
+ * function handles tasks, that are not needed to run through masterNode. To make them run smooth without waiting for other tasks to be completed, we moved them in separate function
+ */
+ function reportEdgeDateTimeAndNumberOfLuminaires() {
+
+ //Number of ok and nok nodes on platform does not equals to total number of nodes.
+ //possible error is, that nodesData object is changing all the time. To make a proper calculation of ok,nok luminaires, we make a copy of it:
+ let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
+
+ const ts = Date.now();
+ const keys = Object.keys(nodesData_clone);
+
+ const number_of_luminaires = keys.length;
+ let number_of_ok_luminaires = 0;
+ let number_of_nok_luminaires = 0;
+
+ for (let i = 0; i < keys.length; i++) {
+ let key = keys[i];
+ let nodeObj = nodesData_clone[key];
+ if (nodeObj.tbname == undefined) continue;
+
+ if (nodeObj.status) number_of_ok_luminaires++;
+ else number_of_nok_luminaires++;
+ }
+
+ const values = {
+ "number_of_luminaires": number_of_luminaires,
+ "number_of_ok_luminaires": number_of_ok_luminaires,
+ "number_of_nok_luminaires": number_of_nok_luminaires,
+ "edge_date_time": ts
+ };
+
+ sendTelemetry(values, SETTINGS.rvoTbName, ts);
+ }
+
+
+ function handleRsPort() {
+
+ //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
+ // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
+ // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
+
+ if (SETTINGS.serial_port == "" || SETTINGS.serial_port == undefined || SETTINGS.serial_port.length === 1) SETTINGS.serial_port = "ttymxc4";
+ rsPort = new SerialPort(`/dev/${SETTINGS.serial_port}`, { autoOpen: false });
+ //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
+ //rsPort.setMaxListeners(0);
+
+ rsPort.on('open', async function() {
+
+ logger.debug("CMD manager - rsPort opened success");
+
+ //loadRelaysData();
+
+ await runSyncExec(`stty -F /dev/${SETTINGS.serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function(status) {
+ instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status);
+
+ logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status);
+
+ //APP START
+ let dataToInfoSender = { id: SETTINGS.project_id, name: SETTINGS.rvo_name };
+ dataToInfoSender.fw_version = SETTINGS.edge_fw_version;
+ dataToInfoSender.startdate = new Date().toISOString().slice(0, 19).replace('T', ' ');
+ dataToInfoSender.__force__ = true;
+
+ instance.send(SEND_TO.infoSender, dataToInfoSender);
+
+ logger.debug(0, "---------------------------->START message send to service", dataToInfoSender);
+
+ }).catch(function(reason) {
+ instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason);
+ });
});
- });
- rsPort.on('error', function(err) {
-
+ rsPort.on('error', function(err) {
+
//TODO report to service!!!
- //errLogger.error(exports.title, "unable to open port", FLOW.OMS_serial_port, err.message);
- errorHandler.sendMessageToService([exports.title, "unable to open port", FLOW.OMS_serial_port, err.message], 0);
+ //errLogger.error(exports.title, "unable to open port", SETTINGS.serial_port, err.message);
+ errorHandler.sendMessageToService([exports.title, "unable to open port", SETTINGS.serial_port, err.message], 0);
instance.send(SEND_TO.debug, err.message);
- });
+ });
- rsPort.on("close", () => {
- rsPort.close();
- });
+ rsPort.on("close", () => {
+ setTimeout(() => rsPort.open(), 1000);
+ });
+
+ rsPort.open();
+ }
- //loadRelaysData();
- rsPort.open();
instance.on("close", () => {
clearInterval(interval);
+ clearInterval(customTasksInterval);
+ clearInterval(setCorrectTime);
rsPort.close();
});
- instance.on("data", async function(flowdata) {
+ instance.on("0", flowdata => {
+ main();
+ })
+
+ instance.on("1", async function(flowdata) {
//instance.send(SEND_TO.debug, "on Data");
//instance.send(SEND_TO.debug, flowdata);
-
+
//logger.debug(flowdata.data);
//just testing functions
- if(flowdata.data == "open")
- {
- if(!rsPort.isOpen) rsPort.open();
+ if (flowdata.data == "open") {
+ if (!rsPort.isOpen) rsPort.open();
return;
}
- else if(flowdata.data == "close")
- {
+ else if (flowdata.data == "close") {
rsPort.close();
return;
}
- else if(flowdata.data == "clean")
- {
+ else if (flowdata.data == "clean") {
tasks = [];
return;
}
- else if(flowdata.data == "buildtasks")
- {
+ else if (flowdata.data == "buildtasks") {
//build & run
return;
}
- else if(flowdata.data == "run")
- {
+ else if (flowdata.data == "run") {
//durations = [];
- if(tasks.length == 0)
- {
+ if (tasks.length == 0) {
buildTasks();
- if(rsPort.isOpen)
- {
- interval = setInterval(runTasks, 100);
+ if (rsPort.isOpen) {
+ interval = setInterval(runTasks, 100);
}
- else
- {
- instance.send(SEND_TO.debug, "port is not opened!!!");
+ else {
+ instance.send(SEND_TO.debug, "port is not opened!!!");
}
}
}
- else
- {
+ else {
//terminal data - object
//logger.debug("flowdata", flowdata.data);
- if(typeof flowdata.data === 'object')
- {
+ if (typeof flowdata.data === 'object') {
//logger.debug("dido", flowdata.data);
- if(flowdata.data.hasOwnProperty("sender"))
- {
+ if (flowdata.data.hasOwnProperty("sender")) {
//data from dido_controller
- if(flowdata.data.sender == "dido_controller")
- {
+ if (flowdata.data.sender == "dido_controller") {
- if(flowdata.data.hasOwnProperty("cmd"))
- {
+ if (flowdata.data.hasOwnProperty("cmd")) {
let cmd = flowdata.data.cmd;
-
- if(cmd == "buildTasks")
- {
+ if (cmd == "buildTasks") {
clearInterval(interval);
logger.debug("-->CMD MANAGER - BUILD TASKS");
@@ -2592,46 +2081,37 @@ exports.install = function(instance) {
logger.debug("-->CMD MANAGER - RUN TASKS");
interval = setInterval(runTasks, LONG_INTERVAL);
}
- else if(cmd == "reload_relays")
- {
+ else if (cmd == "reload_relays") {
loadRelaysData(flowdata.data.line);
- if(flowdata.data.dataChanged)
- {
- if(!flowdata.data.value)
- {
+ if (flowdata.data.dataChanged) {
+ if (!flowdata.data.value) {
reportOfflineNodeStatus(flowdata.data.line);
}
- else
- {
+ else {
reportOnlineNodeStatus(flowdata.data.line);
}
}
-
+
}
- else if(cmd == "rotary_switch_state")
- {
+ else if (cmd == "rotary_switch_state") {
+ let value = flowdata.data.value;
+
//state was changed
- if(rotary_switch_state != flowdata.data.value)
- {
- if(rotary_switch_state == "Off")
- {
+ if (rotary_switch_state != value) {
+ if (value == "Off") {
//vyreportovat vsetky svietdla
reportOfflineNodeStatus();
}
- else reportOnlineNodeStatus();
+ rotary_switch_state = value;
}
-
- rotary_switch_state = flowdata.data.value;
}
- else if(cmd == "lux_sensor")
- {
+ else if (cmd == "lux_sensor") {
lux_sensor = parseInt(flowdata.data.value);
// POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ??
- if(lux_sensor < 100)
- {
+ if (lux_sensor < 100) {
// we send lux_sensor value to all nodes:
let params = getParams(PRIORITY_TYPES.node_broadcast);
@@ -2650,70 +2130,41 @@ exports.install = function(instance) {
tasks.push(params);
-
//process profiles
turnOnOffLinesAccordingToLuxSensor(lux_sensor);
}
}
- else if(cmd == "state_of_breaker")
- {
+ else if (cmd == "state_of_breaker") {
//istic linie
let value = flowdata.data.value;
let line = parseInt(flowdata.data.line);
let dataChanged = false;
- if(state_of_breaker[line] != value) dataChanged = true;
+ if (state_of_breaker[line] != value) dataChanged = true;
state_of_breaker[line] = value;
let status = "OK";
- let weight = ERRWEIGHT.NOTICE;
- let message = `zapnutý istič línie č. ${line}`;
- if(value == "Off")
- {
- weight = ERRWEIGHT.ERROR;
- message = `vypnutý istič línie č. ${line}`;
- status = "NOK";
- }
+ if (value == "Off") status = "NOK";
- if(dataChanged) {
+ if (dataChanged) {
- if(relaysData.hasOwnProperty(line))
- {
+ if (relaysData.hasOwnProperty(line)) {
let tbname = relaysData[line].tbname;
- if(value == "Off") sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_off_line", {line: line}, "", SEND_TO.tb, instance, "circuit_breaker");
- else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", {line: line}, "", SEND_TO.tb, instance, "circuit_breaker");
+ if (value == "Off") sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_off_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
+ else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
//report status liniu
- let values = {
- "status": status
- };
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //instance.send(SEND_TO.tb, dataToTb);
- tbHandler.sendToTb(dataToTb, instance);
+ sendTelemetry({ status: status }, tbname)
//current value
- if(value == "Off")
- {
- //vyreportovat vsetky svietdla na linii
- reportOfflineNodeStatus(line);
- }
- else reportOnlineNodeStatus(line);
+ if (value == "Off") reportOfflineNodeStatus(line); //vyreportovat vsetky svietidla na linii
}
}
}
- else{
+ else {
logger.debug("undefined cmd", cmd);
}
}
@@ -2723,15 +2174,18 @@ exports.install = function(instance) {
}
//data from worksys
- if(flowdata.data.hasOwnProperty("topic"))
- {
+ if (flowdata.data.hasOwnProperty("topic")) {
- let data = flowdata.data.content.data;
+ let data = getNested(flowdata.data, "content", "data");
+ if (data == undefined) {
+ console.log("Invalid rpc command came from platform");
+ return;
+ }
let command = data.params.command;
let method = data.method;
let profile = data.params.payload;
- if(profile == undefined) profile = "";
+ if (profile == undefined) profile = "";
let entity = data.params.entities[0];
let entity_type = entity.entity_type;
let tbname = entity.tb_name;
@@ -2740,185 +2194,171 @@ exports.install = function(instance) {
logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
logger.debug("----------------------------");
- if(entity_type == "street_luminaire"|| entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4")
- {
- if(method == "set_command")
- {
+ if (entity_type == "street_luminaire" || entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") {
+ if (method == "set_command") {
//let command = data.params.command;
let value = data.params.payload.value;
-
- if(command == "dimming")
- {
+
+ if (command == "dimming") {
let nodeWasFound = false;
let keys = Object.keys(nodesData);
//logger.debug("-----", keys);
- for(let i = 0; i < keys.length; i++)
- {
+ for (let i = 0; i < keys.length; i++) {
let node = keys[i];
//logger.debug( node, nodesData[node], tbname);
- if(tbname == nodesData[node].tbname.trim())
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
+ if (tbname == nodesData[node].tbname) {
+ let params = getParams(PRIORITY_TYPES.high_priority);
- value = parseInt(value);
- if(value > 0) value = value + 128;
+ value = parseInt(value);
+ if (value > 0) value = value + 128;
- //set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime
- params.type = "cmd";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;//dimming
- params.recipient = 1;//slave
- params.byte4 = value;
- params.rw = 1;//write
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'set dimming from platform';
- //params.debug = true;
+ //set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;//dimming
+ params.recipient = 1;//slave
+ params.byte4 = value;
+ params.rw = 1;//write
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'set dimming from platform';
+ //params.debug = true;
- //ak linia je
+ //ak linia je
- //debug(params);
- logger.debug("dimming", params);
+ //debug(params);
+ logger.debug("dimming", params);
- tasks.push(params);
+ tasks.push(params);
- setTimeout(function(){
+ setTimeout(function() {
- //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority
- //a pridame aj vyreportovanie dimmingu
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
+ //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority
+ //a pridame aj vyreportovanie dimmingu
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
- params.type = "cmd";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;//dimming
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read dimming (after set dimming from platform)';
- params.debug = true;
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;//dimming
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read dimming (after set dimming from platform)';
+ params.debug = true;
- tasks.push(params);
- }
+ tasks.push(params);
+ }
- //pridame aj vyreportovanie - vykon
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
+ //pridame aj vyreportovanie - vykon
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
- params.type = "cmd";
- params.tbname = tbname;
- params.address = node;
- params.register = 76;
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Power (after set dimming from platform)';
- params.debug = true;
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 76;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Power (after set dimming from platform)';
+ params.debug = true;
- tasks.push(params);
- }
+ tasks.push(params);
+ }
- //pridame aj vyreportovanie - prud svietidla
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
+ //pridame aj vyreportovanie - prud svietidla
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
- params.type = "cmd";
- params.tbname = tbname;
- params.address = node;
- params.register = 75;
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Current (after set dimming from platform)';
- params.debug = true;
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 75;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Current (after set dimming from platform)';
+ params.debug = true;
- tasks.push(params);
- }
+ tasks.push(params);
+ }
- //pridame aj vyreportovanie - power faktor - ucinnik
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
+ //pridame aj vyreportovanie - power faktor - ucinnik
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
- params.type = "cmd";
- params.tbname = tbname;
- params.address = node;
- params.register = 77;
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read power factor - Cos phi (after set dimming from platform)';
- params.debug = true;
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 77;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read power factor - Cos phi (after set dimming from platform)';
+ params.debug = true;
- tasks.push(params);
- }
+ tasks.push(params);
+ }
- },4000);
-
+ }, 4000);
- nodeWasFound = true;
- break;
+ nodeWasFound = true;
+
+ break;
}
}
- if(!nodeWasFound)
- {
+ if (!nodeWasFound) {
logger.debug("set dimming from platform", "unable to find tbname", tbname);
}
}
- else
- {
+ else {
instance.send(SEND_TO.debug, "undefined command " + command);
logger.debug("undefined command", command);
}
return;
}
- else if(method == "set_profile")
- {
+ else if (method == "set_profile") {
//nastav profil nodu
logger.debug("-->set_profile for node", data.params);
logger.debug("------profile data", profile);
//instance.send(SEND_TO.debug, "set_profile" + command);
let keys = Object.keys(nodesData);
- for(let i = 0; i < keys.length; i++)
- {
+ for (let i = 0; i < keys.length; i++) {
let node = keys[i];
- if(tbname == nodesData[node].tbname.trim())
- {
+ if (tbname == nodesData[node].tbname) {
- if(profile != "") profile = JSON.stringify(profile);
+ if (profile != "") profile = JSON.stringify(profile);
dbNodes.modify({ processed: false, profile: profile }).where("node", node).make(function(builder) {
builder.callback(function(err, response) {
- logger.debug("worksys - update node profile done", profile);
- if(profile === "") logger.debug("worksys - update node profile done - profile is empty");
+ logger.debug("worksys - update node profile done", profile);
+ if (profile === "") logger.debug("worksys - update node profile done - profile is empty");
- //profil úspešne prijatý pre node č. xx
- //sendNotification("CMD manager", tbname, ERRWEIGHT.INFO, `profil úspešne poslaný z platformy na RVO pre node č. ${node}`, profile, SEND_TO.tb, instance, null );
- sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", {node: node}, profile, SEND_TO.tb, instance );
+ //profil úspešne prijatý pre node č. xx
+ sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", { node: node }, profile, SEND_TO.tb, instance);
- nodesData[node].processed = false;
- nodesData[node].profile = profile;
+ nodesData[node].processed = false;
+ nodesData[node].profile = profile;
- let line = nodesData[node].line;
- processNodeProfile(node);
-
- });
+ processNodeProfile(node);
});
+ });
}
}
}
- else
- {
+ else {
instance.send(SEND_TO.debug, "unknown method " + method);
logger.debug("unknown method", method);
@@ -2928,28 +2368,24 @@ exports.install = function(instance) {
}
//nastav profil linie z platformy
- else if(entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se")
- {
+ else if (entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se") {
//profil linie
//relays.table line:number|tbname:string|contactor:number|profile:string
//najdeme line relaysData
- if(method == "set_profile")
- {
+ if (method == "set_profile") {
logger.debug("-->set_profile for line", data.params);
logger.debug("profile data:", profile);
let keys = Object.keys(relaysData);
- for(let i = 0; i < keys.length; i++)
- {
+ for (let i = 0; i < keys.length; i++) {
let line = keys[i];
- if(tbname == relaysData[line].tbname)
- {
+ if (tbname == relaysData[line].tbname) {
//zmazeme tasky
- removeTask({type: "relay", line: line});
-
- if(profile != "") profile = JSON.stringify(profile);
+ removeTask({ type: "relay", line: line });
+
+ if (profile != "") profile = JSON.stringify(profile);
dbRelays.modify({ profile: profile }).where("line", line).make(function(builder) {
builder.callback(function(err, response) {
@@ -2958,12 +2394,18 @@ exports.install = function(instance) {
logger.debug("worksys - update relay profile done:", profile);
instance.send(SEND_TO.debug, "worksys - update relay profile done");
- loadRelaysData(line).then(function (data) {
- logger.debug("loadRelaysData DONE for line", line);
- buildTasks({processLineProfiles: true, line: line});
- });
-
- sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", {line: line}, profile, SEND_TO.tb, instance );
+ relaysData[line].profile = profile;
+
+ loadRelaysData(line)
+
+ //TODO build tasks by mala bezat az ked je vsetko loadRelaysData
+ //spracovane, pravdepodobne treba spravit promisy
+ logger.debug("loadRelaysData DONE for line", line);
+ console.log("zacina buildTasks po loadRelaysData.........")
+
+ buildTasks({ processLineProfiles: true, line: line });
+
+ sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", { line: line }, profile, SEND_TO.tb, instance);
});
});
@@ -2971,35 +2413,31 @@ exports.install = function(instance) {
}
}
}
- else if(method == "set_command")
- {
+ else if (method == "set_command") {
let value = data.params.payload.value;
- if(command === "switch")
- {
+ if (command === "switch") {
- // if we receive rpc from platform, to switch maintenance mode, we set OMS_maintenance_mode flow variable to value;
- if(entity_type === "edb" || entity_type === "edb_ver4_se") FLOW.variables.OMS_maintenance_mode = value;
-
- let responseRelays = await promisifyBuilder(dbRelays.find().where("tbname", tbname));
+ // if we receive rpc from platform, to switch maintenance mode, we set SETTINGS.maintenance_mode flow variable to value;
+ if (entity_type === "edb" || entity_type === "edb_ver4_se") SETTINGS.maintenance_mode = value;
+ const relayObject = getObjectByTbValue(relaysData, tbname);
let line = 0;
- if(responseRelays.length == 1) line = responseRelays[0].line;
-
- if(value == false) turnOffLine(line, "command received form platform");
- else turnOnLine(line, "command received form platform");
+ if (isObject(relayObject)) line = relayObject.line;
+
+ // v relaysData je contactor bud 0 alebo 1, ale z platformy prichadza true, false;
+ if (value == false) turnLine("off", line, "command received from platform");
+ else turnLine("on", line, "command received from platform");
}
}
- else
- {
+ else {
instance.send(SEND_TO.debug, "undefined method " + method);
logger.debug("undefined method", method);
}
return;
}
- else
- {
+ else {
instance.send(SEND_TO.debug, "UNKNOW entity_type " + entity_type);
logger.debug("UNKNOW entity_type", entity_type);
}
@@ -3007,11 +2445,10 @@ exports.install = function(instance) {
}
//terminal
- if(!rsPort.isOpen) await rsPort.open();
+ if (!rsPort.isOpen) await rsPort.open();
let params = flowdata.data.body;
- if(params == undefined)
- {
+ if (params == undefined) {
//logger.debug("CMD manager flowdata.data.body is undefined");
return;
}
@@ -3032,7 +2469,7 @@ exports.install = function(instance) {
cleanUpRefFlowdataObj();
- refFlowdataObj[ timestamp ] = flowdata;
+ refFlowdataObj[timestamp] = flowdata;
//fix
//params.address = params.adress;
@@ -3049,745 +2486,500 @@ exports.install = function(instance) {
}
})
+
+ //function gets value of a nested property in an object and returns undefined if it does not exists:
+ function getNested(obj, ...args) {
+ return args.reduce((obj, level) => obj && obj[level], obj)
+ }
+
+
+ /**
+ * setCorrectTime function runs once per hour
+ * If it is 3 o'clock, it sets actual time, which is got from services
+ * https://service-prod01.worksys.io/gettime
+ * If also detects Read Only Filesystem once a day
+ */
+ function setCorrectPlcTimeOnceADay() {
+
+ const currentTime = new Date();
+ if (currentTime.getHours() != 3) return;
+
+ RESTBuilder.make(function(builder) {
+
+ if (!builder) return;
+
+ builder.method('GET');
+ builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
+
+ builder.callback(function(err, response, output) {
+
+ if (err) {
+ console.log(err);
+ return;
+ }
+
+ const res = output.response;
+
+ try {
+
+ const obj = JSON.parse(res);
+ let d = new Date(obj.date);
+
+ const now = new Date();
+
+ let diffInMinutes = now.getTimezoneOffset();
+ console.log("---->TimezoneOffset", diffInMinutes);
+
+ if (d instanceof Date) {
+
+ // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
+
+ let year = d.getFullYear();
+ let month = addZeroBefore(d.getMonth() + 1);
+ let day = addZeroBefore(d.getDate());
+
+ let hours = addZeroBefore(d.getHours());
+ let minutes = addZeroBefore(d.getMinutes());
+ let seconds = addZeroBefore(d.getSeconds());
+
+ let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+
+ exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+ console.log(dateStr);
+
+ monitor.info("failed timedatectl set-time", err, stderr);
+ }
+ else {
+ monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
+ }
+
+ });
+ }
+
+ } catch (error) {
+ logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
+ monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
+ }
+
+ // we detect readOnlyFileSystem once an hour as well
+ detectReadOnlyFilesystem();
+
+ });
+ });
+
+ }
+
+
+ function detectReadOnlyFilesystem() {
+ exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+
+ } else {
+ //console.log("Read-only", stdout);
+
+ let lines = stdout + "";
+ lines = lines.split("\n");
+
+ let readOnlyDetected = "";
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("/dev/mmcblk0p2")) {
+ readOnlyDetected = lines[i];
+ }
+ }
+
+ if (readOnlyDetected !== "") {
+ errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
+ monitor.info("Read only filesystem detected");
+ }
+
+ }
+ });
+ }
+
+
+
+
+
+
+
+
+ ///helper functions
+ function sendTelemetry(values, tbname, date = Date.now()) {
+ const dataToTb = {
+ [tbname]: [
+ {
+ "ts": date,
+ "values": values
+ }
+ ]
+ }
+
+ tbHandler.sendToTb(dataToTb, instance);
+ }
+
+ function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) {
+
+ if (date === undefined) date = new Date();
+ //if(duskOffset === undefined) duskOffset = 0;
+ //if(dawnOffset === undefined) dawnOffset = 0;
+
+ //let line = keys[i];
+ let profilestr = "";
+ if (relaysData[line] != undefined) profilestr = relaysData[line].profile;
+
+ let result = {};
+
+ var times = SunCalc.getTimes(date, latitude, longitude);
+ let dawn = new Date(times.sunrise);//usvit
+ let dusk = new Date(times.sunset);//sumrak
+
+
+ //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
+ //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
+
+
+ let dusk_astro_clock_offset = duskOffset;//minutes
+ let dawn_astro_clock_offset = dawnOffset;//minutes
+
+ try {
+
+ let profile = JSON.parse(profilestr);
+ if (Object.keys(profile).length === 0) throw ("profile is not defined");
+
+ //Jednoduchý režim
+ if (profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) {
+
+ }
+
+ //Režim astrohodín
+ if (profile.astro_clock == true) {
+ //if(profile.dusk_lux_sensor == false)
+ {
+ if (profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt(profile.dusk_astro_clock_offset);
+ }
+
+ //if(profile.dawn_lux_sensor == false)
+ {
+ if (profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt(profile.dawn_astro_clock_offset);
+ }
+
+ }
+
+ //dusk - súmrak
+ //down, sunrise - svitanie
+
+ } catch (error) {
+ if (profilestr != "") {
+ logger.debug(profilestr);
+ logger.debug(error);
+ }
+ }
+
+ result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
+
+ dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset * 60000);
+ dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset * 60000);
+
+ result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dusk_hours = dusk.getHours();
+ result.dusk_minutes = dusk.getMinutes();
+
+ result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
+ result.dawn_hours = dawn.getHours();
+ result.dawn_minutes = dawn.getMinutes();
+
+ result.dusk_time = dusk.getTime();
+ result.dawn_time = dawn.getTime();
+
+ result.dusk_astro_clock_offset = dusk_astro_clock_offset;
+ result.dawn_astro_clock_offset = dawn_astro_clock_offset;
+
+ return result;
+ }
+
+
+ function processResponse(register, bytes) {
+
+ let values = {};
+
+ let byte3 = bytes[0];
+ let byte2 = bytes[1];
+ let byte1 = bytes[2];
+ let byte0 = bytes[3];
+
+ //status
+ if (register == 0) {
+ let statecode = bytesToInt(bytes);
+ values = { "statecode": statecode };
+ return values;
+ }
+
+ //Dimming, CCT
+ if (register == 1) {
+ let brightness = 0;
+ let dimming = byte0;
+ if (dimming > 128) {
+ //dimming = -128;
+ brightness = dimming - 128;
+ }
+
+ //cct
+ //Ak Byte3 == 1: CCT = (Byte2*256)+Byte1
+ let cct;
+ if (byte3 == 1) cct = byte2 * 256 + byte1;
+ else cct = bytesToInt(bytes.slice(0, 3));
+
+ //cct podla auditu
+
+ values["dimming"] = brightness;
+ return values;
+ }
+
+ //
+ if (register == 4) {
+ values["master_node_version"] = bytes[1] + "." + bytes[2];
+ //logger.debug("FW Version", register, bytes);
+ }
+
+ //Napätie
+ if (register == 74) {
+ let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
+ values["voltage"] = Number(voltage);
+ }
+
+ //Prúd
+ if (register == 75) {
+ let current = bytesToInt(bytes);
+ values["current"] = current;
+ }
+
+ //výkon
+ if (register == 76) {
+ let power = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["power"] = Number(power);
+ }
+
+ //účinník
+ if (register == 77) {
+ let power_factor = Math.cos(bytesToInt(bytes) * 0.1).toFixed(2);
+ values["power_factor"] = Number(power_factor);
+ }
+
+ //frekvencia
+ if (register == 78) {
+ let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["frequency"] = Number(frequency);
+ }
+
+ //energia
+ if (register == 79) {
+ let energy = bytesToInt(bytes);
+
+ //Energiu treba reportovať v kWh. Teda číslo, ktoré príde treba podeliť 1000. Toto som ti možno zle napísal.
+
+ values["energy"] = energy / 1000;
+ }
+
+ //doba života
+ if (register == 80) {
+ let lifetime = (bytesToInt(bytes) / 60).toFixed(2);
+ values["lifetime"] = Number(lifetime);
+ }
+
+ //nastavenie profilu
+ if (register == 8) {
+ let time_schedule_settings = bytesToInt(bytes);
+ values["time_schedule_settings"] = time_schedule_settings;
+ }
+
+ //skupinová adresa 1
+ if (register == 3) {
+ let gr_add_1 = bytesToInt(byte0);
+ values["gr_add_1"] = gr_add_1;
+
+ let gr_add_2 = bytesToInt(byte1);
+ values["gr_add_2"] = gr_add_2;
+
+ let gr_add_3 = bytesToInt(byte2);
+ values["gr_add_3"] = gr_add_3;
+
+ let gr_add_4 = bytesToInt(byte3);
+ values["gr_add_4"] = gr_add_4;
+ }
+
+ //naklon
+ if (register == 84) {
+ let temp;
+ if (byte3 >= 128) {
+ temp = (byte3 - 128) * (-1);
+ }
+ else {
+ temp = byte3;
+ }
+
+ let inclination_x;
+ if (byte2 >= 128) {
+ inclination_x = (byte2 - 128) * (-1);
+ }
+ else {
+ inclination_x = byte2;
+ }
+
+ let inclination_y;
+ if (byte1 >= 128) {
+ inclination_y = (byte1 - 128) * (-1);
+ }
+ else {
+ inclination_y = byte1;
+ }
+
+ let inclination_z;
+ if (byte0 >= 128) {
+ inclination_z = (byte0 - 128) * (-1);
+ }
+ else {
+ inclination_z = byte0;
+ }
+
+ values["temperature"] = temp;
+
+ //náklon x
+ values["inclination_x"] = inclination_x;
+
+ //náklon y
+ values["inclination_y"] = inclination_y;
+
+ //náklon z
+ values["inclination_z"] = inclination_z;
+ }
+
+ let h = byte3;
+ let m = byte2;
+
+ let timestamp;
+
+ if (register == 87 || register == 6 || register == 7) {
+ //if(byte3 < 10) h = "0" + byte3;
+ //if(byte2 < 10) m = "0" + byte2;
+ //if(byte1 < 10) s = "0" + byte1;
+
+ var d = new Date();
+ d.setHours(h, m, 0);
+ timestamp = d.getTime();
+ }
+
+ //aktuálny čas
+ if (register == 87) {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["actual_time"] = h + ":" + m + ":" + s;
+
+ values["actual_time"] = timestamp;
+ }
+
+ //čas súmraku
+ if (register == 6) {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["dusk_time"] = h + ":" + m + ":" + s;
+
+ values["dusk_time"] = timestamp;
+ }
+
+ //čas úsvitu
+ if (register == 7) {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["dawn_time"] = h + ":" + m + ":" + s;
+
+ values["dawn_time"] = timestamp;
+ }
+
+ //FW verzia
+ if (register == 89) {
+ //formát: "Byte3: Byte2.Byte1 (Byte0)"
+ values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
+ }
+
+ return values;
+ }
+
+
+ //byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
+ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
+ let resp = [];
+
+ let cmd = register;
+
+ if (typeof adresa === 'string') adresa = parseInt(adresa);
+ if (typeof byte1 === 'string') byte1 = parseInt(byte1);
+ if (typeof byte2 === 'string') byte2 = parseInt(byte2);
+ if (typeof byte3 === 'string') byte3 = parseInt(byte3);
+ if (typeof byte4 === 'string') byte4 = parseInt(byte4);
+
+ if (rw === 0) {
+ cmd = cmd + 0x8000;
+ }
+
+ //master
+ if (rec === 0) adresa = 0;
+
+ if (rec === 2) {
+ adresa = 0xffffffff;//Broadcast
+ }
+
+ //recipient
+ if (rec === 3) {
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(adresa & 0xFF);//band
+ }
+ else {
+ resp.push((adresa >> 24) & 0xFF);//rshift
+ resp.push((adresa >> 16) & 0xFF);
+ resp.push((adresa >> 8) & 0xFF);
+ resp.push(adresa & 0xFF);
+
+ if (rec === 2) {
+ resp.push(0xFF);
+ }
+ else resp.push(0);
+ }
+
+ resp.push((cmd >> 8) & 0xFF);//rshift
+ resp.push(cmd & 0xFF);//band
+ resp.push(byte1 & 0xFF);//band
+ resp.push(byte2 & 0xFF);//band
+ resp.push(byte3 & 0xFF);//band
+ resp.push(byte4 & 0xFF);//band
+
+ //let data = '12345';
+ let crc = crc16('ARC', resp);
+ let c1 = (crc >> 8) & 0xFF;
+ let c2 = crc & 0xFF;
+
+ resp.push(c1);
+ resp.push(c2);
+
+ //logger.debug("checksum", crc);
+ //logger.debug("resp", resp);
+
+ return resp;
+
+ }
+
+ function getObjectByTbValue(object, tbname) {
+ return object[Object.keys(object).find(key => object[key].tbname === tbname)];
+ }
+
+ function isObject(item) {
+ return (typeof item === "object" && !Array.isArray(item) && item !== null);
+ }
+
} // end of instance.export
-
-/**
- * setCorrectTime function runs once per hour
- * If it is 3 o'clock, it sets actual time, which is got from services
- * https://service-prod01.worksys.io/gettime
- * If also detects Read Only Filesystem once a day
- */
-function setCorrectPlcTimeOnceADay()
-{
-
- const currentTime = new Date();
- if(currentTime.getHours() != 3) return;
-
- RESTBuilder.make(function(builder) {
-
- if(!builder) return;
-
- builder.method('GET');
- builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
-
- builder.callback(function(err, response, output) {
-
- if (err) {
- console.log(err);
- return;
- }
-
- const res = output.response;
-
- try {
-
- const obj = JSON.parse(res);
- let d = new Date(obj.date);
-
- const now = new Date();
-
- let diffInMinutes = now.getTimezoneOffset();
- console.log("---->TimezoneOffset", diffInMinutes);
-
- if(d instanceof Date)
- {
-
- // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
-
- let year = d.getFullYear();
- let month = addZeroBefore(d.getMonth() + 1);
- let day = addZeroBefore(d.getDate());
-
- let hours = addZeroBefore(d.getHours());
- let minutes = addZeroBefore(d.getMinutes() );
- let seconds = addZeroBefore(d.getSeconds());
-
- let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-
- exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
- console.log(dateStr);
-
- monitor.info("failed timedatectl set-time", err, stderr);
- }
- else
- {
- monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
- }
-
- });
- }
-
- } catch (error) {
- logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
- monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
- }
-
- // we detect readOnlyFileSystem once an hour as well
- detectReadOnlyFilesystem();
-
- });
- });
-
-}
-
-
-function detectReadOnlyFilesystem()
-{
- exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
-
- } else {
- //console.log("Read-only", stdout);
-
- let lines = stdout + "";
- lines = lines.split("\n");
-
- let readOnlyDetected = "";
- for(let i = 0; i < lines.length; i++)
- {
- if(lines[i].startsWith("/dev/mmcblk0p2"))
- {
- readOnlyDetected = lines[i];
- }
- }
-
- if(readOnlyDetected !== "")
- {
- errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
- monitor.info("Read only filesystem detected");
- }
-
- }
- });
-}
-
-let setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
-setCorrectPlcTimeOnceADay();
-
-
-
-
-
-
-
-
-
-///helper functions
-
-function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0)
-{
-
- if(date === undefined) date = new Date();
- //if(duskOffset === undefined) duskOffset = 0;
- //if(dawnOffset === undefined) dawnOffset = 0;
-
- //let line = keys[i];
- let profilestr = "";
- if(relaysData[line] != undefined) profilestr = relaysData[line].profile;
-
- let result = {};
-
- var times = SunCalc.getTimes(date, latitude, longitude);
- let dawn = new Date(times.sunrise);//usvit
- let dusk = new Date(times.sunset);//sumrak
-
-
- //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
- //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
-
-
- let dusk_astro_clock_offset = duskOffset;//minutes
- let dawn_astro_clock_offset = dawnOffset;//minutes
-
- try {
-
- let profile = JSON.parse(profilestr);
- if(Object.keys(profile).length === 0) throw ("profile is not defined");
-
- //Jednoduchý režim
- if(profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false)
- {
-
- }
-
- //Režim astrohodín
- if(profile.astro_clock == true)
- {
- //if(profile.dusk_lux_sensor == false)
- {
- if(profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt( profile.dusk_astro_clock_offset );
- }
-
- //if(profile.dawn_lux_sensor == false)
- {
- if(profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt( profile.dawn_astro_clock_offset );
- }
-
- }
-
- //dusk - súmrak
- //down, sunrise - svitanie
-
- } catch (error) {
- if(profilestr != "")
- {
- logger.debug(profilestr);
- logger.debug(error);
- }
- }
-
- result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
-
- dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset*60000);
- dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset*60000);
-
- result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dusk_hours = dusk.getHours();
- result.dusk_minutes = dusk.getMinutes();
-
- result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
- result.dawn_hours = dawn.getHours();
- result.dawn_minutes = dawn.getMinutes();
-
- result.dusk_time = dusk.getTime();
- result.dawn_time = dawn.getTime();
-
- result.dusk_astro_clock_offset = dusk_astro_clock_offset;
- result.dawn_astro_clock_offset = dawn_astro_clock_offset;
-
- return result;
-}
-
-
-function processResponse(register, bytes)
-{
-
- let values = {};
-
- let byte3 = bytes[0];
- let byte2 = bytes[1];
- let byte1 = bytes[2];
- let byte0 = bytes[3];
-
- //status
- if(register == 0)
- {
- let statecode = bytesToInt(bytes);
- values = {"statecode": statecode};
- return values;
- }
-
- //Dimming, CCT
- if(register == 1)
- {
- let brightness = 0;
- let dimming = byte0;
- if(dimming > 128) {
- //dimming = -128;
- brightness = dimming - 128;
- }
-
- //cct
- //Ak Byte3 == 1: CCT = (Byte2*256)+Byte1
- let cct;
- if(byte3 == 1) cct = byte2*256 + byte1;
- else cct = bytesToInt(bytes.slice(0, 3));
-
- //cct podla auditu
-
- values["dimming"] = brightness;
- return values;
- }
-
- //
- if(register == 4)
- {
- values["master_node_version"] = bytes[1] + "." + bytes[2];
- //logger.debug("FW Version", register, bytes);
- }
-
- //Napätie
- if(register == 74)
- {
- let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
- values["voltage"] = Number(voltage);
- }
-
- //Prúd
- if(register == 75)
- {
- let current = bytesToInt(bytes);
- values["current"] = current;
- }
-
- //výkon
- if(register == 76)
- {
- let power = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["power"] = Number(power);
- }
-
- //účinník
- if(register == 77)
- {
- let power_factor = Math.cos(bytesToInt(bytes) * 0.1).toFixed(2);
- values["power_factor"] = Number(power_factor);
- }
-
- //frekvencia
- if(register == 78)
- {
- let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["frequency"] = Number(frequency);
- }
-
- //energia
- if(register == 79)
- {
- let energy = bytesToInt(bytes);
-
- //Energiu treba reportovať v kWh. Teda číslo, ktoré príde treba podeliť 1000. Toto som ti možno zle napísal.
-
- values["energy"] = energy / 1000;
- }
-
- //doba života
- if(register == 80)
- {
- let lifetime = ( bytesToInt(bytes) / 60).toFixed(2);
- values["lifetime"] = Number(lifetime);
- }
-
- //nastavenie profilu
- if(register == 8)
- {
- let time_schedule_settings = bytesToInt(bytes);
- values["time_schedule_settings"] = time_schedule_settings;
- }
-
- //skupinová adresa 1
- if(register == 3)
- {
- let gr_add_1 = bytesToInt(byte0);
- values["gr_add_1"] = gr_add_1;
-
- let gr_add_2 = bytesToInt(byte1);
- values["gr_add_2"] = gr_add_2;
-
- let gr_add_3 = bytesToInt(byte2);
- values["gr_add_3"] = gr_add_3;
-
- let gr_add_4 = bytesToInt(byte3);
- values["gr_add_4"] = gr_add_4;
- }
-
- //naklon
- if(register == 84)
- {
- let temp;
- if(byte3 >= 128)
- {
- temp = (byte3 - 128) * (-1);
- }
- else
- {
- temp = byte3;
- }
-
- let inclination_x;
- if(byte2 >= 128)
- {
- inclination_x = (byte2 - 128) * (-1);
- }
- else
- {
- inclination_x = byte2;
- }
-
- let inclination_y;
- if(byte1 >= 128)
- {
- inclination_y = (byte1 - 128) * (-1);
- }
- else
- {
- inclination_y = byte1;
- }
-
- let inclination_z;
- if(byte0 >= 128)
- {
- inclination_z = (byte0 - 128) * (-1);
- }
- else
- {
- inclination_z = byte0;
- }
-
- values["temperature"] = temp;
-
- //náklon x
- values["inclination_x"] = inclination_x;
-
- //náklon y
- values["inclination_y"] = inclination_y;
-
- //náklon z
- values["inclination_z"] = inclination_z;
- }
-
- let h = byte3;
- let m = byte2;
- let s = byte1;
-
- let timestamp;
-
- if(register == 87 || register == 6 || register == 7 )
- {
- //if(byte3 < 10) h = "0" + byte3;
- //if(byte2 < 10) m = "0" + byte2;
- //if(byte1 < 10) s = "0" + byte1;
-
- var d = new Date();
- d.setHours(h);
- d.setMinutes(m);
- d.setSeconds(s);
-
- timestamp = d.getTime();
- }
-
- //aktuálny čas
- if(register == 87)
- {
- //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
- //values["actual_time"] = h + ":" + m + ":" + s;
-
- values["actual_time"] = timestamp;
- }
-
- //čas súmraku
- if(register == 6)
- {
- //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
- //values["dusk_time"] = h + ":" + m + ":" + s;
-
- values["dusk_time"] = timestamp;
- }
-
- //čas úsvitu
- if(register == 7)
- {
- //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
- //values["dawn_time"] = h + ":" + m + ":" + s;
-
- values["dawn_time"] = timestamp;
- }
-
- //FW verzia
- if(register == 89)
- {
- //formát: "Byte3: Byte2.Byte1 (Byte0)"
- values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
- }
-
- return values;
-}
-
-
-//byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
-function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
- let resp = [];
-
- let cmd = register;
-
- if (typeof adresa === 'string') adresa = parseInt(adresa);
- if (typeof byte1 === 'string') byte1 = parseInt(byte1);
- if (typeof byte2 === 'string') byte2 = parseInt(byte2);
- if (typeof byte3 === 'string') byte3 = parseInt(byte3);
- if (typeof byte4 === 'string') byte4 = parseInt(byte4);
-
- if (rw === 0)
- {
- cmd = cmd + 0x8000;
- }
-
- //master
- if(rec === 0) adresa = 0;
-
- if(rec === 2)
- {
- adresa = 0xffffffff;//Broadcast
- }
-
- //recipient
- if (rec === 3)
- {
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push( adresa & 0xFF );//band
- }
- else
- {
- resp.push( (adresa >> 24) & 0xFF);//rshift
- resp.push( (adresa >> 16) & 0xFF);
- resp.push( (adresa >> 8) & 0xFF);
- resp.push( adresa & 0xFF );
-
- if (rec === 2)
- {
- resp.push(0xFF);
- }
- else resp.push(0);
- }
-
- resp.push( (cmd >> 8) & 0xFF);//rshift
- resp.push( cmd & 0xFF );//band
- resp.push( byte1 & 0xFF );//band
- resp.push( byte2 & 0xFF );//band
- resp.push( byte3 & 0xFF );//band
- resp.push( byte4 & 0xFF );//band
-
- //let data = '12345';
- let crc = crc16('ARC', resp);
- let c1 = (crc >> 8) & 0xFF;
- let c2 = crc & 0xFF;
-
- resp.push(c1);
- resp.push(c2);
-
- //logger.debug("checksum", crc);
- //logger.debug("resp", resp);
-
- return resp;
-
-}
-
-
-
-
-
-
-// SAMPLE DATA
-
-const relaysDataExample =
-{
- '0': {
- line: 0,
- tbname: 'jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV',
- contactor: 1,
- profile: ''
- },
- '1': {
- line: 1,
- tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O',
- contactor: 1,
- profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
- },
- '2': {
- line: 2,
- tbname: 'jBL12pg63eX4N9P7zy0lJLyEJKmlbkGwZMx0avQV',
- contactor: 1,
- profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
- },
- '3': {
- line: 3,
- tbname: 'aAOzENGrvpbe0VoK7D6E1a819PZmdg3nl24JLQMk',
- contactor: 1,
- profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
- }
-}
-
-
-const rpcSwitchOffLine =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 8,
- "method": "set_command",
- "params": {
- "entities": [
- {
- "entity_type": "edb_line",
- "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
- }
- ],
- "command": "switch",
- "payload": {
- "value": false
- }
- }
- }
- }
-}
-
-const rpcSetNodeDimming =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 10,
- "method": "set_command",
- "params": {
- "entities": [
- {
- "entity_type": "street_luminaire",
- "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
- }
- ],
- "command": "dimming",
- "payload": {
- "value": 5
- }
- }
- }
- }
-}
-
-const rpcLineProfile =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 9,
- "method": "set_profile",
- "params": {
- "entities": [
- {
- "entity_type": "edb_line",
- "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
- }
- ],
- "payload": {
- "intervals": [
- {
- "value": 0,
- "end_time": "20:00",
- "start_time": "13:00"
- },
- {
- "value": 1,
- "end_time": "05:30",
- "start_time": "20:00"
- },
- {
- "value": 0,
- "end_time": "13:00",
- "start_time": "05:30"
- }
- ],
- "astro_clock": true,
- "dawn_lux_sensor": false,
- "dusk_lux_sensor": false,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 0,
- "dusk_astro_clock_offset": 0,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
- }
- }
- }
- }
-}
-
-
-const rpcNodeProfile =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 11,
- "method": "set_profile",
- "params": {
- "entities": [
- {
- "entity_type": "street_luminaire",
- "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
- }
- ],
- "payload": {
- "intervals": [
- {
- "cct": 3000,
- "value": 0,
- "end_time": "17:50",
- "start_time": "13:00"
- },
- {
- "cct": 3000,
- "value": 100,
- "end_time": "21:30",
- "start_time": "17:50"
- },
- {
- "cct": 3000,
- "value": 0,
- "end_time": "13:00",
- "start_time": "07:10"
- },
- {
- "cct": 3000,
- "value": 50,
- "end_time": "00:00",
- "start_time": "21:30"
- },
- {
- "cct": 3000,
- "value": 10,
- "end_time": "04:30",
- "start_time": "00:00"
- },
- {
- "cct": 3000,
- "value": 100,
- "end_time": "07:10",
- "start_time": "04:30"
- }
- ],
- "astro_clock": true,
- "dawn_lux_sensor": false,
- "dusk_lux_sensor": false,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 30,
- "dusk_astro_clock_offset": 20,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
- }
- }
- }
- }
-}
-
- const sunCalcExample = {
- dusk_no_offset: '20:18',
- dawn_no_offset: '05:19',
- dusk: '20:18',
- dusk_hours: 20,
- dusk_minutes: 18,
- dawn: '05:19',
- dawn_hours: 5,
- dawn_minutes: 19,
- dusk_time: 1715278688962,
- dawn_time: 1715224744357,
- dusk_astro_clock_offset: 0,
- dawn_astro_clock_offset: 0
-}
diff --git a/flow/csv_import.js b/flow/csv_import.js
deleted file mode 100644
index 5ae1e68..0000000
--- a/flow/csv_import.js
+++ /dev/null
@@ -1,175 +0,0 @@
-exports.id = 'csv_import';
-exports.title = 'CsvImport';
-exports.version = '1.0.0';
-exports.group = 'Worksys';
-exports.color = '#2134B0';
-exports.input = 1;
-exports.output = ["red", "white"];
-exports.click = false;
-exports.author = 'Daniel Segeš';
-exports.icon = 'file-import';
-exports.options = { edge: "undefined" };
-
-exports.html = ``;
-
-exports.readme = `# load csv to table db`;
-
-//config
-let delimiter = ";";
-let uniqueColumn = "node";
-let path = "flow/audit_test_panel.csv";
-let startFrom = 1;
-let table = "nodes";
-let mapImport = {
- 2: "node",
- 4: "tbname",
- 3: "line"
-};
-
-//10.0.0.62
-delimiter = ";";
-uniqueColumn = "node";
-path = "flow/audit_rvo14_lampy.csv";
-startFrom = 1;
-table = "nodes";
-mapImport = {
- 1: "node",
- 3: "tbname",
- 2: "line"
-};
-
-//notification
-delimiter = ";";
-uniqueColumn = undefined;
-path = "flow/notifikacie.csv";
-startFrom = 1;
-table = "notifications";
-mapImport = {
- 0: "key",
- 1: "weight",
- 2: "en",
- 3: "sk"
-};
-
-const fs = require('fs');
-
-exports.install = function(instance) {
-
- //console.log("csv import installed");
-
- instance.on("close", () => {
-
- })
-
-
- instance.on("data", (flowdata) => {
-
- instance.send(0, "start import");
- console.log("csv import", flowdata.data);
-
- //{table: "nodes", startFrom: 1, delimiter: ";", uniqueColumn: "node", path: "flow/audit_rvo14_lampy.csv", mapImport: {1: "node", 3: "tbname", 2: "line"}}
-
-
- if(typeof flowdata.data === 'object')
- {
- console.log("*******************", flowdata.data);
-
- if(!flowdata.data.hasOwnProperty("table"))
- {
- instance.send(0, "!!!!csv import - nedefinovana tabulka");
- return;
- }
-
- if(!flowdata.data.hasOwnProperty("uniqueColumn"))
- {
- //instance.send(0, "!!!!csv import - nedefinovane uniqueColumn");
- //return;
- }
-
- if(!flowdata.data.hasOwnProperty("path"))
- {
- instance.send(0, "!!!!csv import - nedefinovana cesta k suboru");
- return;
- }
-
- if(!flowdata.data.hasOwnProperty("mapImport"))
- {
- instance.send(0, "!!!!csv import - nedefinovany mapImport");
- return;
- }
-
- table = flowdata.data.table;
- uniqueColumn = flowdata.data.uniqueColumn;
- if(uniqueColumn === "") uniqueColumn = undefined;
-
- path = flowdata.data.path;
- mapImport = flowdata.data.mapImport;
-
- if(flowdata.data.hasOwnProperty("delimiter")) delimiter = flowdata.data.delimiter;
- if(flowdata.data.hasOwnProperty("startFrom")) startFrom = flowdata.data.startFrom;
- }
-
-
- var db = TABLE(table);
- db.clear();
-
- let keys = Object.keys(mapImport);
-
- try {
- const data = fs.readFileSync(path, 'utf8')
-
- let lines = data.split("\n");
-
- for(let i = startFrom; i < lines.length; i++)
- {
- let line = lines[i];
- if(line === "") continue;
-
- let data = line.split(delimiter);
- if(data.length == 0) continue;
-
- let insertData = {};
-
- keys.map(function(key){
- let k = mapImport[key];
-
- //console.log("importineg", i, key, k);
-
- if(data[key] != undefined) insertData[k] = data[key].trim();
- else{
- console.log("undefined", key, data);
- }
- });
-
- console.log("insertData", insertData);
-
- if(uniqueColumn != undefined)
- {
- db.insert(insertData, true).where(uniqueColumn, insertData[uniqueColumn]);
- }
- else
- {
- db.insert(insertData);
- }
-
-
- }
-
- console.log("csv import finished");
- instance.send(0, "csv import finished");
-
- } catch (err) {
- console.error(err)
- instance.send(0, err);
- }
- })
-
-}
-
-
diff --git a/flow/db_init.js b/flow/db_init.js
new file mode 100644
index 0000000..e44e7b8
--- /dev/null
+++ b/flow/db_init.js
@@ -0,0 +1,107 @@
+exports.id = 'db_init';
+exports.title = 'DB Initialization';
+exports.group = 'Worksys';
+exports.color = '#888600';
+exports.version = '1.0.2';
+exports.icon = 'sign-out';
+exports.input = 1;
+exports.output = ["blue"];
+
+exports.html = `
+
+
+
Hostname or IP address (if not empty - setting will override db setting)
+
+
+
+
+
`;
+
+
+exports.readme = `
+# DB initialization
+`;
+
+const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
+const { initNotification } = require('./helper/notification_reporter');
+
+
+exports.install = async function(instance) {
+
+ const dbNodes = TABLE("nodes");
+ const dbRelays = TABLE("relays");
+ const dbSettings = TABLE("settings");
+ const dbStatus = TABLE("status");
+ const dbPins = TABLE("pins");
+ const dbNotifications = TABLE("notifications");
+
+ FLOW.GLOBALS = {};
+ const dbs = FLOW.GLOBALS;
+
+ const responseSettings = await promisifyBuilder(dbSettings.find());
+ const responseNodes = await promisifyBuilder(dbNodes.find());
+ const responsePins = await promisifyBuilder(dbPins.find());
+ const responseStatus = await promisifyBuilder(dbStatus.find());
+ const responseRelays = await promisifyBuilder(dbRelays.find());
+ const response = await promisifyBuilder(dbNotifications.find());
+
+ dbs.pinsData = makeMapFromDbResult(responsePins, "pin");
+ dbs.relaysData = makeMapFromDbResult(responseRelays, "line");
+ dbs.nodesData = makeMapFromDbResult(responseNodes, "node");
+ dbs.statusData = responseStatus[0];
+ dbs.notificationsData = makeMapFromDbResult(response, "key");
+
+ //+|354|nodesdata.....+|482|nodesdata....
+ //for some reason, if last line in nodes.table is not empty, flow wrote more nodes data in one row,
+ //so we have to add empty line at the bottom of nodes table to avoid this.
+ //now, remove empty lines from nodesData database:
+ if(dbs.nodesData.hasOwnProperty("0")) delete dbs.nodesData["0"];
+
+ dbs.settings = {
+ edge_fw_version : "2024-10-14", //rok-mesiac-den
+ language : responseSettings[0]["lang"],
+ rvo_name : responseSettings[0]["rvo_name"],
+ project_id : responseSettings[0]["project_id"],
+ rvoTbName : dbs.relaysData[0]["tbname"],
+ temperature_address : responseSettings[0]["temperature_address"],
+ controller_type : responseSettings[0]["controller_type"],
+ serial_port : responseSettings[0]["serial_port"],
+ node_status_nok_time : responseSettings[0]["node_status_nok_time"] * 60 * 60 * 1000 ,// hour * minutes *
+ latitude : responseSettings[0]["latitude"],
+ longitude : responseSettings[0]["longitude"],
+ no_voltage : new Set(),//modbus_citysys - elektromer
+ backup_on_failure : responseSettings[0]["backup_on_failure"],
+ restore_from_backup : responseSettings[0]["restore_from_backup"],
+ restore_backup_wait : responseSettings[0]["restore_backup_wait"],
+ mqtt_host : responseSettings[0]["mqtt_host"],
+ mqtt_clientid : responseSettings[0]["mqtt_clientid"],
+ mqtt_username : responseSettings[0]["mqtt_username"],
+ mqtt_port : responseSettings[0]["mqtt_port"],
+
+ //dynamic values
+ masterNodeIsResponding : true, //cmd_manager
+ maintenance_mode : false,
+ }
+
+ FLOW.dbLoaded = true;
+ initNotification();
+
+ setTimeout(()=> {
+ console.log("DB_INIT - data loaded");
+ instance.send(0, "_")
+ }, 5000)
+
+};
+
+
+
+
diff --git a/flow/designer.json b/flow/designer.json
index 7d57d69..d0a868d 100644
--- a/flow/designer.json
+++ b/flow/designer.json
@@ -20,13 +20,94 @@
}
],
"components": [
+ {
+ "id": "1611938185451",
+ "component": "modbus_citysys",
+ "tab": "1611921777196",
+ "name": "Modbus_citysys",
+ "x": 118.5,
+ "y": 111.5,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1611951142547"
+ }
+ ],
+ "1": [
+ {
+ "index": "0",
+ "id": "1730283489001"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1612772119611"
+ },
+ {
+ "index": "0",
+ "id": "1730283489001"
+ }
+ ],
+ "3": [
+ {
+ "index": "0",
+ "id": "1611938192035"
+ },
+ {
+ "index": "0",
+ "id": "1730283344075"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Running",
+ "color": "green"
+ },
+ "options": {
+ "edge": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV"
+ },
+ "color": "#2134B0",
+ "notes": ""
+ },
+ {
+ "id": "1611938192035",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "to dido",
+ "x": 804.5,
+ "y": 290.5,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
{
"id": "1611951142547",
"component": "debug",
"tab": "1611921777196",
"name": "ERROR",
- "x": 401,
- "y": 31,
+ "x": 700,
+ "y": 26,
"connections": {},
"disabledio": {
"input": [],
@@ -44,13 +125,37 @@
"color": "#DA4453",
"notes": ""
},
+ {
+ "id": "1612772119611",
+ "component": "virtualwireout",
+ "tab": "1611921777196",
+ "name": "tb-push",
+ "x": 718.75,
+ "y": 213.5,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "tb-push",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "tb-push"
+ },
+ "color": "#303E4D",
+ "notes": ""
+ },
{
"id": "1612776786008",
"component": "wsmqttpublish",
"tab": "1612772287426",
"name": "WS MQTT publish",
- "x": 311.75,
- "y": 248,
+ "x": 338.75,
+ "y": 185,
"connections": {
"0": [
{
@@ -80,7 +185,9 @@
]
},
"disabledio": {
- "input": [],
+ "input": [
+ 1
+ ],
"output": []
},
"state": {
@@ -88,8 +195,8 @@
"color": "green"
},
"options": {
- "username": "",
- "clientid": "",
+ "username": "xmRd6RJxW53WZe4vMFLU",
+ "clientid": "showroom_test_panel_led",
"port": "1883",
"host": ""
},
@@ -101,12 +208,12 @@
"component": "virtualwirein",
"tab": "1612772287426",
"name": "tb-push",
- "x": 68.75,
- "y": 269,
+ "x": 67.75,
+ "y": 273,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1612776786008"
},
{
@@ -134,8 +241,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "to TB",
- "x": 317.75,
- "y": 154,
+ "x": 341.75,
+ "y": 324,
"connections": {},
"disabledio": {
"input": [
@@ -160,8 +267,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "errors from MQTT Broker",
- "x": 610,
- "y": 111,
+ "x": 648,
+ "y": 151,
"connections": {},
"disabledio": {
"input": [
@@ -186,8 +293,8 @@
"component": "debug",
"tab": "1615551125555",
"name": "Debug",
- "x": 755,
- "y": 19,
+ "x": 788,
+ "y": 78,
"connections": {},
"disabledio": {
"input": [
@@ -212,8 +319,8 @@
"component": "virtualwireout",
"tab": "1615551125555",
"name": "tb-push",
- "x": 753,
- "y": 112,
+ "x": 784,
+ "y": 170,
"connections": {},
"disabledio": {
"input": [],
@@ -233,9 +340,9 @@
"id": "1615798582262",
"component": "debug",
"tab": "1615551125555",
- "name": "CMD_debug",
- "x": 750,
- "y": 197,
+ "name": "data to TB",
+ "x": 784,
+ "y": 259,
"connections": {},
"disabledio": {
"input": [
@@ -259,24 +366,22 @@
"id": "1615802995322",
"component": "debug",
"tab": "1611921777196",
- "name": "Debug",
- "x": 398.8833312988281,
- "y": 528.3500061035156,
+ "name": "thermoDido",
+ "x": 738.8833312988281,
+ "y": 717.3500061035156,
"connections": {},
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
- "text": "Disabled",
+ "text": "Enabled",
"color": "gray"
},
"options": {
"type": "data",
"repository": false,
- "enabled": false
+ "enabled": true
},
"color": "#967ADC",
"notes": ""
@@ -285,14 +390,12 @@
"id": "1615809128443",
"component": "debug",
"tab": "1611921777196",
- "name": "Debug",
- "x": 401.8833312988281,
- "y": 625.3500061035156,
+ "name": "thermoTb",
+ "x": 595.8833312988281,
+ "y": 497.3500061035156,
"connections": {},
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
@@ -312,8 +415,8 @@
"component": "virtualwireout",
"tab": "1611921777196",
"name": "tb-push",
- "x": 400.8833312988281,
- "y": 328.25,
+ "x": 749.8833312988281,
+ "y": 610.25,
"connections": {},
"disabledio": {
"input": [],
@@ -334,17 +437,13 @@
"component": "httproute",
"tab": "1615551125555",
"name": "POST /terminal",
- "x": 72,
- "y": 350,
+ "x": 71,
+ "y": 444,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1619515097737"
- },
- {
- "index": "0",
- "id": "1684060205000"
}
]
},
@@ -380,8 +479,8 @@
"component": "httpresponse",
"tab": "1615551125555",
"name": "HTTP Response",
- "x": 751,
- "y": 273,
+ "x": 782,
+ "y": 342,
"connections": {},
"disabledio": {
"input": [],
@@ -397,198 +496,17 @@
"color": "#5D9CEC",
"notes": ""
},
- {
- "id": "1617104731852",
- "component": "debug",
- "tab": "1615551125555",
- "name": "DIDO_Debug",
- "x": 739,
- "y": 635,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- },
- "color": "#967ADC",
- "notes": ""
- },
- {
- "id": "1617114651703",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOff line",
- "x": 71,
- "y": 829,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {
- "data": "{line: 3, command: \"turnOff\", force: true}",
- "datatype": "object"
- },
- "color": "#F6BB42",
- "notes": ""
- },
- {
- "id": "1617115013095",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "tb-push",
- "x": 741,
- "y": 736,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "options": {
- "wirename": "tb-push"
- },
- "color": "#303E4D",
- "notes": ""
- },
- {
- "id": "1617178324650",
- "component": "debug",
- "tab": "1615551125555",
- "name": "Debug",
- "x": 605,
- "y": 1024,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- },
- "color": "#967ADC",
- "notes": ""
- },
- {
- "id": "1617179044099",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "start import",
- "x": 235,
- "y": 1032,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1617180390661"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {
- "datatype": "object",
- "data": "{table: \"konsberg_production_line_operations_error\", startFrom: 1, delimiter: \";\", uniqueColumn: \"\", path: \"flow/operations_error.csv\", mapImport: {0: \"production_line\",\t1: \"operation\", 2: \"error_type\", 3: \"error_code\", 4: \"error_text\", 5: \"error_text_user_defined\"}}"
- },
- "color": "#F6BB42",
- "notes": ""
- },
- {
- "id": "1617180390661",
- "component": "csv_import",
- "tab": "1615551125555",
- "name": "CsvImport",
- "x": 414,
- "y": 1013,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1617178324650"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {
- "edge": "undefined"
- },
- "color": "#2134B0",
- "notes": ""
- },
- {
- "id": "1617197763128",
- "component": "comment",
- "tab": "1615551125555",
- "name": "import data from csv",
- "x": 401,
- "y": 946,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {},
- "color": "#704cff",
- "notes": ""
- },
{
"id": "1617284749681",
"component": "trigger",
"tab": "1615551125555",
"name": "update profile / node",
- "x": 80,
- "y": 13,
+ "x": 95,
+ "y": 107,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1619515097737"
}
]
@@ -613,12 +531,12 @@
"component": "trigger",
"tab": "1615551125555",
"name": "tun tasks",
- "x": 77,
- "y": 84,
+ "x": 82,
+ "y": 183,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1619515097737"
}
]
@@ -642,8 +560,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "wsmqtt-exit1",
- "x": 610.8833312988281,
- "y": 199,
+ "x": 670.8833312988281,
+ "y": 242,
"connections": {},
"disabledio": {
"input": [],
@@ -666,8 +584,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "wsmqtt-exit2",
- "x": 611.8833312988281,
- "y": 374,
+ "x": 685.8833312988281,
+ "y": 434,
"connections": {},
"disabledio": {
"input": [
@@ -687,40 +605,22 @@
"color": "#967ADC",
"notes": ""
},
- {
- "id": "1618393583970",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "to-cmd-manager",
- "x": 740.8833312988281,
- "y": 828,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "from-dido-controller",
- "color": "gray"
- },
- "options": {
- "wirename": "from-dido-controller"
- },
- "color": "#303E4D",
- "notes": ""
- },
{
"id": "1618393674428",
"component": "virtualwirein",
"tab": "1615551125555",
"name": "platform-rpc-call",
- "x": 77.88333129882812,
- "y": 173,
+ "x": 76.88333129882812,
+ "y": 270,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1619515097737"
+ },
+ {
+ "index": "0",
+ "id": "1729630658131"
}
]
},
@@ -738,57 +638,24 @@
"color": "#303E4D",
"notes": ""
},
- {
- "id": "1618393759854",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "cmd_to_dido",
- "x": 76.88333129882812,
- "y": 678,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1683664161036"
- },
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "cmd_to_dido",
- "color": "gray"
- },
- "options": {
- "wirename": "cmd_to_dido"
- },
- "color": "#303E4D",
- "notes": ""
- },
{
"id": "1618393827655",
"component": "virtualwireout",
"tab": "1615551125555",
- "name": "cmd_to_dido",
- "x": 748.8833312988281,
- "y": 373,
+ "name": "cmd-to-dido",
+ "x": 780.8833312988281,
+ "y": 446,
"connections": {},
"disabledio": {
"input": [],
"output": []
},
"state": {
- "text": "cmd_to_dido",
+ "text": "cmd-to-dido",
"color": "gray"
},
"options": {
- "wirename": "cmd_to_dido"
+ "wirename": "cmd-to-dido"
},
"color": "#303E4D",
"notes": ""
@@ -798,8 +665,8 @@
"component": "virtualwireout",
"tab": "1612772287426",
"name": "platform-rpc-call",
- "x": 611.8833312988281,
- "y": 287,
+ "x": 674.8833312988281,
+ "y": 338,
"connections": {},
"disabledio": {
"input": [],
@@ -815,43 +682,13 @@
"color": "#303E4D",
"notes": ""
},
- {
- "id": "1618572059773",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOn line",
- "x": 72,
- "y": 756,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {
- "datatype": "object",
- "data": "{line: 1, command: \"turnOn\", force: true}"
- },
- "color": "#F6BB42",
- "notes": ""
- },
{
"id": "1619515097737",
"component": "cmd_manager",
"tab": "1615551125555",
"name": "CMD Manager",
- "x": 420,
- "y": 156,
+ "x": 435,
+ "y": 126,
"connections": {
"0": [
{
@@ -905,17 +742,13 @@
"component": "httproute",
"tab": "1615551125555",
"name": "GET db",
- "x": 73,
- "y": 455,
+ "x": 65,
+ "y": 549,
"connections": {
"0": [
{
- "index": "0",
+ "index": "1",
"id": "1619515097737"
- },
- {
- "index": "0",
- "id": "1684060205000"
}
]
},
@@ -950,13 +783,13 @@
"component": "trigger",
"tab": "1615551125555",
"name": "turnOnAlarm",
- "x": 68,
- "y": 902,
+ "x": 53,
+ "y": 842,
"connections": {
"0": [
{
"index": "1",
- "id": "1699963668903"
+ "id": "1730323243484"
}
]
},
@@ -980,13 +813,13 @@
"component": "trigger",
"tab": "1615551125555",
"name": "turnOffAlarm",
- "x": 67,
- "y": 975,
+ "x": 50,
+ "y": 928,
"connections": {
"0": [
{
"index": "1",
- "id": "1699963668903"
+ "id": "1730323243484"
}
]
},
@@ -1009,20 +842,20 @@
"id": "1621340721628",
"component": "virtualwireout",
"tab": "1611921777196",
- "name": "modbus_to_dido",
- "x": 399,
- "y": 433,
+ "name": "modbus-to-dido",
+ "x": 921,
+ "y": 404,
"connections": {},
"disabledio": {
"input": [],
"output": []
},
"state": {
- "text": "modbus_to_dido",
+ "text": "modbus-to-dido",
"color": "gray"
},
"options": {
- "wirename": "modbus_to_dido"
+ "wirename": "modbus-to-dido"
},
"color": "#303E4D",
"notes": ""
@@ -1032,8 +865,8 @@
"component": "httproute",
"tab": "1615551125555",
"name": "POST /db_connector",
- "x": 1107,
- "y": 338,
+ "x": 20,
+ "y": 1443,
"connections": {
"0": [
{
@@ -1072,8 +905,8 @@
"component": "db_connector",
"tab": "1615551125555",
"name": "DbConnector",
- "x": 1363,
- "y": 395,
+ "x": 276,
+ "y": 1500,
"connections": {
"1": [
{
@@ -1101,8 +934,8 @@
"component": "httpresponse",
"tab": "1615551125555",
"name": "HTTP Response",
- "x": 1588,
- "y": 454,
+ "x": 501,
+ "y": 1559,
"connections": {},
"disabledio": {
"input": [],
@@ -1121,8 +954,8 @@
"component": "monitormemory",
"tab": "1612772287426",
"name": "RAM",
- "x": 71.88333129882812,
- "y": 609.5,
+ "x": 112.88333129882812,
+ "y": 797.5,
"connections": {
"0": [
{
@@ -1136,12 +969,12 @@
"output": []
},
"state": {
- "text": "834.19 MB / 985.68 MB",
+ "text": "192.45 MB / 249 MB",
"color": "gray"
},
"options": {
"enabled": true,
- "interval": 30000
+ "interval": 20000
},
"color": "#F6BB42",
"notes": ""
@@ -1151,8 +984,8 @@
"component": "monitordisk",
"tab": "1612772287426",
"name": "disk",
- "x": 72.88333129882812,
- "y": 706.5,
+ "x": 114.88333129882812,
+ "y": 895.5,
"connections": {
"0": [
{
@@ -1166,13 +999,13 @@
"output": []
},
"state": {
- "text": "5.84 GB / 7.26 GB",
+ "text": "5.92 GB / 7.22 GB",
"color": "gray"
},
"options": {
"enabled": true,
"path": "/",
- "interval": 30000
+ "interval": 20000
},
"color": "#F6BB42",
"notes": ""
@@ -1182,8 +1015,8 @@
"component": "virtualwirein",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 5.883331298828125,
- "y": 1069.5,
+ "x": -11.116668701171875,
+ "y": 1207.5,
"connections": {
"0": [
{
@@ -1191,7 +1024,7 @@
"id": "1634463186563"
},
{
- "index": "0",
+ "index": "1",
"id": "1634488120710"
}
]
@@ -1215,8 +1048,8 @@
"component": "virtualwireout",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 428.8833312988281,
- "y": 602.5,
+ "x": 507.8833312988281,
+ "y": 815.5,
"connections": {},
"disabledio": {
"input": [],
@@ -1237,8 +1070,8 @@
"component": "virtualwireout",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 612.8833312988281,
- "y": 462.5,
+ "x": 686.8833312988281,
+ "y": 530.5,
"connections": {},
"disabledio": {
"input": [],
@@ -1259,9 +1092,8 @@
"component": "httprequest",
"tab": "1612772287426",
"name": "http://192.168.252.2:8004/sentmessage",
- "reference": "",
- "x": 439.8833312988281,
- "y": 1076.7333374023438,
+ "x": 508.8833312988281,
+ "y": 1134.7333374023438,
"connections": {
"0": [
{
@@ -1291,8 +1123,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 234.75,
- "y": 1024,
+ "x": 242.75,
+ "y": 1248,
"connections": {},
"disabledio": {
"input": [
@@ -1317,8 +1149,8 @@
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 255,
- "y": 512,
+ "x": 299,
+ "y": 730,
"connections": {
"0": [
{
@@ -1352,8 +1184,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 430,
- "y": 508,
+ "x": 481,
+ "y": 726,
"connections": {},
"disabledio": {
"input": [
@@ -1378,8 +1210,8 @@
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 244,
- "y": 608,
+ "x": 305,
+ "y": 817,
"connections": {
"0": [
{
@@ -1413,8 +1245,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 431,
- "y": 700,
+ "x": 482,
+ "y": 906,
"connections": {},
"disabledio": {
"input": [
@@ -1439,8 +1271,8 @@
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 247,
- "y": 702,
+ "x": 301,
+ "y": 910,
"connections": {
"0": [
{
@@ -1474,8 +1306,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 434,
- "y": 792,
+ "x": 482,
+ "y": 1003,
"connections": {},
"disabledio": {
"input": [
@@ -1500,8 +1332,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Send info",
- "x": 438,
- "y": 1185,
+ "x": 509,
+ "y": 1245,
"connections": {},
"disabledio": {
"input": [
@@ -1527,7 +1359,7 @@
"tab": "1612772287426",
"name": "Info sender",
"x": 233,
- "y": 1122,
+ "y": 1148,
"connections": {
"0": [
{
@@ -1559,8 +1391,8 @@
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 811.8833312988281,
- "y": 1070.5,
+ "x": 1038.8833312988281,
+ "y": 1090.5,
"connections": {},
"disabledio": {
"input": [
@@ -1585,8 +1417,8 @@
"component": "virtualwireout",
"tab": "1615551125555",
"name": "send-to-services",
- "x": 748,
- "y": 464,
+ "x": 781,
+ "y": 550,
"connections": {},
"disabledio": {
"input": [],
@@ -1607,8 +1439,8 @@
"component": "monitorconsumption",
"tab": "1612772287426",
"name": "CPU",
- "x": 71,
- "y": 515,
+ "x": 109,
+ "y": 713,
"connections": {
"0": [
{
@@ -1622,7 +1454,7 @@
"output": []
},
"state": {
- "text": "1.9% / 86.94 MB",
+ "text": "40.6% / 47.36 MB",
"color": "gray"
},
"options": {
@@ -1631,53 +1463,23 @@
"monitorsize": true,
"monitorconsumption": true,
"enabled": true,
- "interval": 30000
+ "interval": 5000
},
"color": "#967ADC",
"notes": ""
},
{
- "id": "1683664161036",
- "component": "debug",
- "tab": "1615551125555",
- "name": "CMDtoDIDO",
- "x": 413,
- "y": 654,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- },
- "color": "#967ADC",
- "notes": ""
- },
- {
- "id": "1683981346282",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "from-dido-controller",
- "x": 71,
- "y": 260,
+ "id": "1725218490415",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "Trigger - dimming 650",
+ "x": 282.8833312988281,
+ "y": 422,
"connections": {
"0": [
{
"index": "0",
- "id": "1619515097737"
- },
- {
- "index": "0",
- "id": "1684055037116"
+ "id": "1618558465485"
}
]
},
@@ -1686,74 +1488,224 @@
"output": []
},
"state": {
- "text": "from-dido-controller",
+ "text": "",
"color": "gray"
},
"options": {
- "wirename": "from-dido-controller"
+ "datatype": "object",
+ "data": "{ \"topic\": \"v1/gateway/rpc\", \"content\": { \"device\": \"KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV\", \"data\": { \"id\": 5, \"method\": \"set_command\", \"params\": { \"entities\": [ { \"entity_type\": \"street_luminaire\", \"tb_name\": \"0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO\" } ], \"command\": \"dimming\", \"payload\": { \"value\": 5 } } } } }"
+ },
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1725287725896",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "Trigger - nodeProfile 650",
+ "x": 283.8833312988281,
+ "y": 498,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1618558465485"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "data": "{ \"topic\": \"v1/gateway/rpc\", \"content\": { \"device\": \"0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO\", \"data\": { \"id\": 11, \"method\": \"set_profile\", \"params\": { \"entities\": [ { \"entity_type\": \"street_luminaire\", \"tb_name\": \"0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO\" } ], \"payload\": { \"intervals\": [ { \"cct\": 3000, \"value\": 0, \"end_time\": \"16:45\",\"start_time\": \"13:00\" }, { \"cct\": 3000, \"value\": 7, \"end_time\": \"17:00\", \"start_time\": \"16:45\"}, { \"cct\": 3000, \"value\": 30, \"end_time\": \"17:15\", \"start_time\": \"17:00\" }, { \"cct\": 3000, \"value\":5, \"end_time\": \"17:30\", \"start_time\": \"17:15\" }, { \"cct\": 3000, \"value\": 0, \"end_time\": \"13:00\", \"start_time\": \"17:30\" }, ], \"astro_clock\": false, \"dawn_lux_sensor\": false, \"dusk_lux_sensor\": false, \"dawn_lux_sensor_value\": 5, \"dusk_lux_sensor_value\": 5, \"dawn_astro_clock_offset\": 30, \"dusk_astro_clock_offset\": 20, \"dawn_lux_sensor_time_window\": 30, \"dusk_lux_sensor_time_window\": 30, \"dawn_astro_clock_time_window\": 60, \"dusk_astro_clock_time_window\": 60 } } } } }",
+ "datatype": "object"
+ },
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1725463389430",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "Trigger - dimming 659",
+ "x": 289.8833312988281,
+ "y": 599,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1618558465485"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "data": "{ \"topic\": \"v1/gateway/rpc\", \"content\": { \"device\": \"KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV\", \"data\": { \"id\": 5, \"method\": \"set_command\", \"params\": { \"entities\": [ { \"entity_type\": \"street_luminaire\", \"tb_name\": \"joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM\" } ], \"command\": \"dimming\", \"payload\": { \"value\": 7 } } } } }",
+ "datatype": "object"
+ },
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1728565522830",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "db-init",
+ "x": 100.88333129882812,
+ "y": 34,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "db-init"
},
"color": "#303E4D",
"notes": ""
},
{
- "id": "1684055037116",
- "component": "debug",
- "tab": "1615551125555",
- "name": "from dido to cmd",
- "x": 423,
- "y": 331,
- "connections": {},
+ "id": "1728981631674",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 65.88333129882812,
+ "y": 170.8000030517578,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1612776786008"
+ }
+ ]
+ },
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
- "text": "Enabled",
+ "text": "db-init",
"color": "gray"
},
"options": {
- "type": "data",
- "repository": false,
- "enabled": true
+ "wirename": "db-init"
},
- "color": "#967ADC",
+ "color": "#303E4D",
"notes": ""
},
{
- "id": "1684060205000",
- "component": "debug",
- "tab": "1615551125555",
- "name": "HTTP routes",
- "x": 423,
- "y": 422,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- },
- "color": "#967ADC",
- "notes": ""
- },
- {
- "id": "1684179110403",
- "component": "debug",
+ "id": "1728981755263",
+ "component": "virtualwirein",
"tab": "1611921777196",
- "name": "MDBToDido",
- "x": 401,
- "y": 118,
+ "name": "db-init",
+ "x": 87.88333129882812,
+ "y": 631.3999938964844,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1732823597895"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "db-init"
+ },
+ "color": "#303E4D",
+ "notes": ""
+ },
+ {
+ "id": "1729356985353",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "show settings",
+ "x": 99.88333129882812,
+ "y": 1531.2000122070312,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1729357628696"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1729357628696",
+ "component": "showdb",
+ "tab": "1612772287426",
+ "name": "Show db data",
+ "x": 364.8833312988281,
+ "y": 1614.2000122070312,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1729357637821"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#888600",
+ "notes": ""
+ },
+ {
+ "id": "1729357637821",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "GLOBALS dbdata",
+ "x": 606.8833312988281,
+ "y": 1628.2000122070312,
"connections": {},
"disabledio": {
"input": [],
@@ -1772,33 +1724,274 @@
"notes": ""
},
{
- "id": "1699963668903",
- "component": "dido_controller",
+ "id": "1729359849748",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "show relays",
+ "x": 98.88333129882812,
+ "y": 1593.2000122070312,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1729357628696"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1729359867511",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "show nodesData",
+ "x": 78.88333129882812,
+ "y": 1667.2000122070312,
+ "connections": {
+ "0": [
+ {
+ "index": "2",
+ "id": "1729357628696"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1729359879876",
+ "component": "trigger",
+ "tab": "1612772287426",
+ "name": "show pins",
+ "x": 83.88333129882812,
+ "y": 1741.2000122070312,
+ "connections": {
+ "0": [
+ {
+ "index": "3",
+ "id": "1729357628696"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1729630658131",
+ "component": "debug",
"tab": "1615551125555",
- "name": "DIDO_Controller",
- "x": 402,
- "y": 736,
+ "name": "fromDIDO",
+ "x": 455,
+ "y": 312,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1729712837697",
+ "component": "db_init",
+ "tab": "1612772287426",
+ "name": "DB Initialization",
+ "x": 72,
+ "y": 47,
"connections": {
"0": [
{
"index": "0",
- "id": "1617104731852"
+ "id": "1729712846867"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#888600",
+ "notes": ""
+ },
+ {
+ "id": "1729712846867",
+ "component": "virtualwireout",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 315.8833312988281,
+ "y": 44.5,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "db-init"
+ },
+ "color": "#303E4D",
+ "notes": ""
+ },
+ {
+ "id": "1730283344075",
+ "component": "code",
+ "tab": "1611921777196",
+ "name": "Code",
+ "x": 380,
+ "y": 287,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1730286332882"
+ },
+ {
+ "index": "0",
+ "id": "1621340721628"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "keepmessage": true,
+ "code": "let b = value.tbdata;\n\nif(b == undefined) return;\nlet key = Object.keys(b)[0];\n\nlet toSend = b[key][0];\ndelete toSend.ts;\ndelete toSend.values.status;\n\nsend(0, toSend);\n\nlet a ={\n \"sender\": \"modbus_citysys\",\n \"tbdata\": {\n \"PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8\": [\n {\n \"ts\": 1730326629980,\n \"values\": {\n \"status\": \"OK\",\n \"Phase_2_voltage\": 233.8,\n \"Phase_3_voltage\": 233,\n \"Phase_1_current\": 0.07,\n \"Phase_2_current\": 0.33,\n \"Phase_3_current\": 0,\n \"Phase_1_power\": 5.3,\n \"Phase_2_power\": 37.1,\n \"Phase_3_power\": 0,\n \"total_power\": 42.4,\n \"total_energy\": 5803.8,\n \"Phase_1_pow_factor\": 0.49,\n \"Phase_2_pow_factor\": 0.86,\n \"Phase_3_pow_factor\": 0,\n \"power_factor\": 0.8\n }\n }\n ]\n }\n}",
+ "outputs": 1
+ },
+ "color": "#656D78",
+ "notes": ""
+ },
+ {
+ "id": "1730283489001",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "modbus tb",
+ "x": 705.5,
+ "y": 113.5,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1730286332882",
+ "component": "debug",
+ "tab": "1611921777196",
+ "name": "modbusCode",
+ "x": 546,
+ "y": 383,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1730323243484",
+ "component": "dido_controller",
+ "tab": "1615551125555",
+ "name": "DIDO_Controller",
+ "x": 403,
+ "y": 959,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1730323814342"
}
],
"1": [
{
"index": "0",
- "id": "1617104731852"
+ "id": "1730323748655"
},
{
"index": "0",
- "id": "1617115013095"
+ "id": "1730323814342"
}
],
"2": [
{
"index": "0",
- "id": "1618393583970"
+ "id": "1730323748661"
}
]
},
@@ -1817,21 +2010,17 @@
"notes": ""
},
{
- "id": "1699964678894",
+ "id": "1730323407563",
"component": "virtualwirein",
"tab": "1615551125555",
- "name": "modbus_to_dido",
- "x": 79,
- "y": 595,
+ "name": "db-init",
+ "x": 56.883331298828125,
+ "y": 1260.2000122070312,
"connections": {
"0": [
{
- "index": "0",
- "id": "1699963668903"
- },
- {
- "index": "0",
- "id": "1699964793925"
+ "index": "2",
+ "id": "1730323243484"
}
]
},
@@ -1840,77 +2029,31 @@
"output": []
},
"state": {
- "text": "modbus_to_dido",
+ "text": "db-init",
"color": "gray"
},
"options": {
- "wirename": "modbus_to_dido"
+ "wirename": "db-init"
},
"color": "#303E4D",
"notes": ""
},
{
- "id": "1699964793925",
- "component": "debug",
+ "id": "1730323590937",
+ "component": "virtualwirein",
"tab": "1615551125555",
- "name": "modbusToDido",
- "x": 411,
- "y": 561,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- },
- "color": "#967ADC",
- "notes": ""
- },
- {
- "id": "1699965957410",
- "component": "modbus_reader",
- "tab": "1611921777196",
- "name": "Modbus reader",
- "x": 102,
- "y": 175,
+ "name": "modbus-to-dido",
+ "x": 53.883331298828125,
+ "y": 760,
"connections": {
"0": [
{
"index": "0",
- "id": "1611951142547"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1621340721628"
+ "id": "1730323243484"
},
{
"index": "0",
- "id": "1684179110403"
- },
- {
- "index": "0",
- "id": "1717441414646"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1615809595184"
- },
- {
- "index": "0",
- "id": "1714752862828"
+ "id": "1730324345047"
}
]
},
@@ -1919,41 +2062,27 @@
"output": []
},
"state": {
- "text": "",
+ "text": "modbus-to-dido",
"color": "gray"
},
- "options": {},
- "color": "#2134B0",
+ "options": {
+ "wirename": "modbus-to-dido"
+ },
+ "color": "#303E4D",
"notes": ""
},
{
- "id": "1700411878636",
- "component": "thermometer",
- "tab": "1611921777196",
- "name": "Thermometer",
- "x": 107.75,
- "y": 449,
+ "id": "1730323631557",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "cmd-to-dido",
+ "x": 47.883331298828125,
+ "y": 1013.2000122070312,
"connections": {
"0": [
{
- "index": "0",
- "id": "1615802995322"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1615809595184"
- },
- {
- "index": "0",
- "id": "1615809128443"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1621340721628"
+ "index": "1",
+ "id": "1730323243484"
}
]
},
@@ -1962,53 +2091,27 @@
"output": []
},
"state": {
- "text": "",
- "color": "gray"
- },
- "options": {},
- "color": "#5CB36D",
- "notes": ""
- },
- {
- "id": "1714752862828",
- "component": "debug",
- "tab": "1611921777196",
- "name": "MDBToTb",
- "x": 402,
- "y": 228,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
+ "text": "cmd-to-dido",
"color": "gray"
},
"options": {
- "type": "data",
- "repository": false,
- "enabled": true
+ "wirename": "cmd-to-dido"
},
- "color": "#967ADC",
+ "color": "#303E4D",
"notes": ""
},
{
- "id": "1717441414646",
- "component": "code",
- "tab": "1611921777196",
- "name": "device-status",
- "x": 588.0833282470703,
- "y": 177,
+ "id": "1730323674816",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOff line",
+ "x": 50,
+ "y": 1090,
"connections": {
"0": [
{
- "index": "0",
- "id": "1717442627834"
- },
- {
- "index": "0",
- "id": "1717442631338"
+ "index": "1",
+ "id": "1730323243484"
}
]
},
@@ -2021,76 +2124,50 @@
"color": "gray"
},
"options": {
- "keepmessage": true,
- "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n}",
- "outputs": 1
+ "datatype": "object",
+ "data": "{line:3, command: \"turnOff\", force: true}"
},
- "color": "#656D78",
+ "color": "#F6BB42",
"notes": ""
},
{
- "id": "1717442627834",
- "component": "debug",
- "tab": "1611921777196",
- "name": "modbus service",
- "x": 802.0833282470703,
- "y": 139,
- "connections": {},
+ "id": "1730323674822",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "turnOn line",
+ "x": 57,
+ "y": 1166,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1730323243484"
+ }
+ ]
+ },
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
- "text": "Enabled",
+ "text": "",
"color": "gray"
},
"options": {
- "type": "data",
- "repository": false,
- "enabled": true
+ "data": "{line:1, command: \"turnOn\", force: true}",
+ "datatype": "object"
},
- "color": "#967ADC",
+ "color": "#F6BB42",
"notes": ""
},
{
- "id": "1717442631338",
+ "id": "1730323748655",
"component": "virtualwireout",
- "tab": "1611921777196",
- "name": "send-to-services",
- "x": 801.0833282470703,
- "y": 236,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "options": {
- "wirename": "send-to-services"
- },
- "color": "#303E4D",
- "notes": ""
- },
- {
- "id": "1718016045116",
- "component": "virtualwirein",
- "tab": "1612772287426",
+ "tab": "1615551125555",
"name": "tb-push",
- "x": 84.75,
- "y": 1300,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016052341"
- }
- ]
- },
+ "x": 720,
+ "y": 1003,
+ "connections": {},
"disabledio": {
"input": [],
"output": []
@@ -2106,80 +2183,34 @@
"notes": ""
},
{
- "id": "1718016052341",
- "component": "slack_filter",
- "tab": "1612772287426",
- "name": "Slack Filter",
- "x": 278,
- "y": 1297,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016086212"
- },
- {
- "index": "0",
- "id": "1718016073501"
- }
- ]
- },
+ "id": "1730323748661",
+ "component": "virtualwireout",
+ "tab": "1615551125555",
+ "name": "to-cmd-manager",
+ "x": 722.8833312988281,
+ "y": 1090,
+ "connections": {},
"disabledio": {
"input": [],
"output": []
},
"state": {
- "text": "Running",
+ "text": "from-dido-controller",
"color": "gray"
},
"options": {
- "slack_channel": "C071KN2Q8SK",
- "tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
- "message_includes": "[\"is responding again\", \"Lamps have turned\", \"Flow has been restarted\"]",
- "types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
- "name": "RVO16 Senica - 10.0.0.131"
+ "wirename": "from-dido-controller"
},
- "color": "#30E193",
+ "color": "#303E4D",
"notes": ""
},
{
- "id": "1718016073501",
- "component": "httprequest",
- "tab": "1612772287426",
- "name": "http://192.168.252.2:8004/slack",
- "x": 471,
- "y": 1354,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016086212"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "options": {
- "stringify": "json",
- "method": "POST",
- "url": "http://192.168.252.2:8004/slack"
- },
- "color": "#5D9CEC",
- "notes": ""
- },
- {
- "id": "1718016086212",
+ "id": "1730323814342",
"component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 808,
- "y": 1302,
+ "tab": "1615551125555",
+ "name": "DidoDebug",
+ "x": 709,
+ "y": 906,
"connections": {},
"disabledio": {
"input": [],
@@ -2198,17 +2229,115 @@
"notes": ""
},
{
- "id": "1718016094070",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "Trigger",
+ "id": "1730324002079",
+ "component": "virtualwirein",
+ "tab": "1615551125555",
+ "name": "from-dido-controller",
"x": 73,
- "y": 1388,
+ "y": 359,
+ "connections": {
+ "0": [
+ {
+ "index": "1",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "from-dido-controller",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "from-dido-controller"
+ },
+ "color": "#303E4D",
+ "notes": ""
+ },
+ {
+ "id": "1730324345047",
+ "component": "debug",
+ "tab": "1615551125555",
+ "name": "toDido",
+ "x": 405,
+ "y": 841,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1730327321896",
+ "component": "virtualwirein",
+ "tab": "1612772287426",
+ "name": "db-init",
+ "x": 4.883331298828125,
+ "y": 1111.8000030517578,
"connections": {
"0": [
{
"index": "0",
- "id": "1718016052341"
+ "id": "1634488120710"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "db-init",
+ "color": "gray"
+ },
+ "options": {
+ "wirename": "db-init"
+ },
+ "color": "#303E4D",
+ "notes": ""
+ },
+ {
+ "id": "1732823597895",
+ "component": "thermometer",
+ "tab": "1611921777196",
+ "name": "Thermometer",
+ "x": 372.75,
+ "y": 602,
+ "connections": {
+ "1": [
+ {
+ "index": "0",
+ "id": "1615809595184"
+ },
+ {
+ "index": "0",
+ "id": "1615809128443"
+ }
+ ],
+ "2": [
+ {
+ "index": "0",
+ "id": "1621340721628"
+ },
+ {
+ "index": "0",
+ "id": "1615802995322"
}
]
},
@@ -2220,11 +2349,8 @@
"text": "",
"color": "gray"
},
- "options": {
- "datatype": "object",
- "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }"
- },
- "color": "#F6BB42",
+ "options": {},
+ "color": "#5CB36D",
"notes": ""
}
],
diff --git a/flow/di_do_controller.js b/flow/di_do_controller.js
new file mode 100644
index 0000000..d006a04
--- /dev/null
+++ b/flow/di_do_controller.js
@@ -0,0 +1,1654 @@
+exports.id = 'di_do_controller';
+exports.title = 'DI_DO_Controller';
+exports.version = '1.0.0';
+exports.group = 'Worksys';
+exports.color = '#2134B0';
+exports.input = 2;
+exports.output = ["red", "white", "yellow","green"];
+exports.click = false;
+exports.icon = 'bolt';
+exports.options = { edge: "undefined" };
+
+exports.html = ``;
+
+exports.readme = `# Sets RS232 port and all digital pins on device. Then it starts to receive data from sensors.
+It receives:
+
+rotary_switch_state,
+rotary_switch_state,
+door_condition,
+state_of_breaker,
+state_of_contactor,
+twilight_sensor
+`;
+
+/*
+we open rsPort "/dev/ttymxc0" and set digital input and output pins with "setRSPortData"
+Currently we are interested in pins no. 1,2,3,6,8,9,10,16
+pins number 11, 12, 13 (we receive 10,11,12 in rsPortReceivedData) are "stykace"
+When port receives data, it must be exactly 4 bytes long. Second byte is pin, that changed its value, fourth byte is value itself.
+After that, we set this value to "previousValues[allPins[whichpin]]" variable
+*/
+
+
+/*
+RVO objekt:
+state_of_main_switch - sem sa bude reportovať stav hlavného ističa : 0-> off 1-> on (toto nie je na platforme, ale Rado to už do entity type doplnil)
+rotary_switch_state - sem by sa mal reportovať stav vstupov manual a auto podľa nasledovnej logiky:
+ Manual = 1 a Auto = 0 -> vyreportuje Manual
+ Manual = 0 a Auto = 0 -> vyreportuje Off
+ Manual = 0 a Auto = 1 -> vyreportuje Automatic
+
+door_condition - tuto ide pin 6, dverový kontakt -> 1 -> vyreportuje Closed, 0 -> vyreportuje Open
+twilight_sensor - hodnotu, ktorú vracia ten analógový vstup (17) treba poslať sem ako float number. Zrejme tu potom pridáme nejaký koeficient prevodu na luxy
+
+zjavne nám v jsone chýba stav hlavného ističa. Musíme to potom doplniť
+
+Na každú líniu:
+state_of_breaker - podľa indexu ističa sa reportuje jeho stav, teda istič 1 na líniu 1: 0-> off 1-> on
+state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda stykač 1 na líniu 1: 0-> off 1-> on
+ momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale tá zmena by sa mala ukázať aj na platforme
+*/
+
+const dbRelays = TABLE("relays");
+const { errLogger, logger, monitor } = require('./helper/logger');
+const SerialPort = require('serialport');
+const WebSocket = require('ws');
+//const { exec } = require('child_process');
+const { runSyncExec } = require('./helper/serialport_helper');
+const { bytesToInt, resizeArray } = require('./helper/utils');
+const { sendNotification } = require('./helper/notification_reporter');
+const bitwise = require('bitwise');
+
+const DataToTbHandler = require('./helper/DataToTbHandler');
+let tbHandler;
+
+const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
+const errorHandler = new ErrorToServiceHandler();
+
+let ws = null;
+let rsPort = null;
+
+let pinsData;
+let relaysData;
+let rvoTbName;
+let GLOBALS; //FLOW global GLOBALS
+let SETTINGS; // GLOBALS.settings
+let controller_type;
+
+let alarmStatus = "OFF";
+
+const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ cmd_manager: 2,
+ init: 3
+}
+
+
+exports.install = function(instance) {
+
+ process.on('uncaughtException', function (err) {
+
+ //TODO send to service
+
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
+
+ errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
+
+ //process.exit(1);
+ })
+
+ let previousValues = {temperature: 0};
+ let rsPortReceivedData = [];
+
+ let twilight_sensor_interval = 5;//minutes
+ let twilight_sensor = [];
+ const twilight_sensor_array = [];
+ let twighlightError = false;
+
+ monitor.info("DI_DO_Relay_Controller installed");
+
+ //key is PIN number , line: 0 = RVO
+ /*
+ let conversionTable = {
+ "1": {tbname: "", type: "state_of_main_switch", "line": 0}, //state_of_main_switch pin1
+ "2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2
+ "3": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha auto = pin3
+ "4": {tbname: "", type: "power_supply", "line": 0},
+ "5": {tbname: "", type: "battery", "line": 0},
+ "6": {tbname: "", type: "door_condition", "line": 0}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open
+ "8": {tbname: "", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on
+ "9": {tbname: "", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on
+ "10": {tbname: "", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on
+ "11": {tbname: "", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on
+ "12": {tbname: "", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on
+ "13": {tbname: "", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on
+ "16": {tbname: "", type: "twilight_sensor", "line": 0}, // twilight_sensor = pin16
+ };
+ */
+
+ //status for calculating Statecodes
+ let deviceStatuses = {};//key is device name: temperature,....
+ deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič
+ deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód
+ deviceStatuses["door_condition"] = "closed";//Dverový kontakt
+ deviceStatuses["rvo"] = {status: "OK"};//elektromer rvo
+ deviceStatuses["temperature"] = "OK";//templomer
+ deviceStatuses["battery"] = "OK";//Batéria
+ deviceStatuses["power_supply"] = "OK";//Zdroj
+ deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding
+ deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze
+
+ deviceStatuses["state_of_breaker"] = {};//"Off";//Istič
+ deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač
+
+
+ function main() {
+
+ GLOBALS = FLOW.GLOBALS;
+ SETTINGS = FLOW.GLOBALS.settings;
+ rvoTbName = SETTINGS.rvoTbName;
+ pinsData = GLOBALS.pinsData;
+ relaysData = GLOBALS.relaysData;
+ statusData = GLOBALS.statusData;
+
+ tbHandler = new DataToTbHandler(SEND_TO.tb)
+ tbHandler.setSender(exports.title);
+
+ controller_type = SETTINGS.controller_type //"lm" or "unipi" //logicMachine
+ if(controller_type == "") controller_type = "lm";
+
+ deviceStatuses["temperature"] = statusData.thermometer;
+
+ console.log(exports.title, "controller type: ", controller_type);
+
+ if(controller_type === "lm")
+ {
+ handleRsPort();
+ }
+ else if(controller_type === "unipi")
+ {
+ handleWebSocket();
+ }
+ else {
+ errLogger.debug("UNKNOWN controller_type:", controller_type);
+ }
+ }
+
+
+ function initialSetting()
+ {
+
+ //force turn off relays
+
+ let keys = Object.keys(pinsData);
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+ let line = pinsData[key].line;
+
+ if(line != undefined)
+ {
+ if(relaysData[line] != undefined)
+ {
+ pinsData[key].tbname = relaysData[line].tbname;
+
+ //relaysData[line].contactor = 0;
+ }
+ else
+ {
+ errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line);
+
+ //sendNotification("set port ", rvoTbName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null );
+ sendNotification("set port ", rvoTbName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
+ }
+ }
+
+ if(pinsData[key].type == "state_of_contactor")
+ {
+
+ let pin = key - 1;
+ if(controller_type === "unipi") pin = key;
+
+ //this will modify database
+ let forceTurnOff = true;
+ turnOffLine(line, pin, forceTurnOff, "turn off on startup");
+ }
+ }
+
+ let values = {};
+ values["edge_fw_version"] = SETTINGS.edge_fw_version;
+ values["maintenance_mode"] = SETTINGS.maintenance_mode;
+ values["status"] = "OK";
+
+ sendTelemetry(values, rvoTbName);
+ instance.send(SEND_TO.init, "_");
+ //instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"});
+
+ let time = 5*1000;
+ setTimeout(function(){
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"});
+
+ sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance );
+ monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
+
+ }, time);
+
+ }
+
+
+ function handleRsPort()
+ {
+ //TODO build according to pins!!!
+ //! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0")
+ const setRSPortData = [0xAA,6,6,6,6,6,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,10,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,15,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0];
+ rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false });
+
+ rsPort.on('error', function(err) {
+ logger.debug("rsPort opened error - failed", err.message);
+ instance.send(SEND_TO.debug, err.message);
+
+ errorHandler.sendMessageToService( exports.title + " rsPort opened error - failed: " + err.message);
+ })
+
+ rsPort.on('open', async function() {
+
+ await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) {
+
+ //set port
+ rsPort.write(Buffer.from(setRSPortData), function(err) {
+ monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
+
+ turnOffAlarm();
+ initialSetting();
+ })
+
+ }).catch(function (reason) {
+ errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason);
+ errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason);
+ });
+
+ });
+
+
+ rsPort.on('data', function (data){
+
+ rsPortReceivedData = [...rsPortReceivedData, ...data];
+
+ if (rsPortReceivedData[0] != 85) {
+ rsPortReceivedData = [];
+ return;
+ }
+
+ let l = rsPortReceivedData.length;
+
+ if (l < 4 ) return;
+
+ if (l > 4 ) {
+
+ // if array length is greater than 4, we take first 4 byte and do the logic, second 4 bytes, do the logic and so on
+ let i, j, temparray, chunk = 4;
+ for ( i = 0, j = l; i < j; i += chunk ) {
+ temparray = rsPortReceivedData.slice(i, i + chunk);
+
+ if ( temparray.length < 4 ){
+ rsPortReceivedData = [...temparray];
+ return;
+ }
+
+ switchLogic(temparray);
+ }
+
+ rsPortReceivedData = [];
+ return;
+ }
+
+ switchLogic(rsPortReceivedData);
+
+ rsPortReceivedData = [];
+
+ });
+
+ rsPort.on("close", () => {
+ rsPort.close();
+ })
+
+ rsPort.open();
+
+ }
+
+
+ function handleWebSocket() {
+
+ console.log("handleWebSocket function called");
+ ws = new WebSocket('ws:/10.0.0.38:1234/ws')
+
+
+ ws.onopen = function open() {
+
+ instance.send(0, exports.title + " running");
+ turnOffAlarm();
+
+ // useTurnOffCounter = true;
+ // turnOffCounter = relaysData.length - 1;
+ initialSetting();
+ ws.send(JSON.stringify({"cmd":"all"}));
+
+ // startRequests();
+ };
+
+// SAMPLE DATA FROM WEBSOCKET
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_07',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_08',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+
+ ws.onmessage = function(data) {
+
+ data = JSON.parse(data.data);
+ // console.log(data)
+
+ // data comes in array except of "temperature" ==> it comes as an object
+ if(!Array.isArray(data))
+ {
+ let value = data['value'];
+
+ // temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB
+ if(Math.abs(previousValues["temperature"] - value) > 0.21 )
+ {
+ const dataToTb = {
+ [rvoTbName]: [
+ {
+ "ts": Date.now(),
+ "values": {temperature: value}
+ }
+ ]
+ };
+
+ deviceStatuses["temperature"] = "OK";
+ previousValues["temperature"] = value;
+ instance.send(SEND_TO.tb, dataToTb);
+ }
+ return;
+ }
+
+ data.map(item => {
+
+ let value = item['value'];
+ let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01"
+
+ if (pin == undefined) return;
+ switchLogic(pin, value);
+ })
+ }
+
+
+ ws.on('error', (err) => {
+ instance.send(SEND_TO.debug, err.message);
+ })
+
+
+ ws.onclose = function(){
+ // connection closed, discard old websocket and create a new one in 5s
+ // stopRequests();
+ ws = null;
+ console.log("ws is null now, reconnecting in 5 seconds");
+ setTimeout(handleWebSocket, 5000);
+ }
+ }
+
+ instance.on("close", () => {
+ if(rsPort) rsPort.close();
+ if(ws) ws.close();
+ })
+
+
+ function getPin(line)
+ {
+ //conversionTable
+ let keys = Object.keys(pinsData);
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+
+ if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line)
+ {
+ if(rsPort) return key - 1;
+ if(ws) return key;
+ }
+ }
+
+ logger.debug("no pin detected");
+
+ return null;
+ }
+
+
+ function turnOnAlarm()
+ {
+ if(SETTINGS.maintenance_mode) return;
+
+ alarmStatus = "ON";
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( 13 );
+ arr.push( 0 );
+ arr.push( 1 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ logger.debug("sirena zapnuta");
+ });
+ }
+ else if(ws)
+ {
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_08", "value": 1};
+ ws.send(JSON.stringify(cmd));
+ logger.debug("sirena zapnuta");
+ }
+ }
+
+
+ function turnOffAlarm()
+ {
+ alarmStatus = "OFF";
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( 13 );
+ arr.push( 0 );
+ arr.push( 0 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ logger.debug("sirena vypnuta");
+ });
+ }
+ else if(ws)
+ {
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_08", "value": 0};
+ ws.send(JSON.stringify(cmd));
+ logger.debug("sirena vypnuta");
+ }
+ }
+
+
+ function reportLineStatus(line)
+ {
+ //Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false).
+ let tbname = relaysData[line].tbname;
+
+ let bits = [];
+
+ if(deviceStatuses["state_of_breaker"][line] == "On")
+ {
+ bits.push(0);
+ }
+ else bits.push(1);
+
+ if(deviceStatuses["state_of_contactor"][line] == "On")
+ {
+ bits.push(0);
+ }
+ else bits.push(1);
+
+ resizeArray(bits, 8, 0);
+
+ let byte = bitwise.byte.write(bits.reverse());
+ //console.log("line", line, bits, byte);
+
+ sendTelemetry({statecode: byte}, tbname);
+ }
+
+
+ function turnOnLine(line, pin, force, info)
+ {
+
+ instance.send(SEND_TO.debug, "turn on line " + line );
+ if(force == undefined) force = false;
+
+ if(line == 0)
+ {
+ if(alarmStatus == "ON") turnOffAlarm();
+ SETTINGS.maintenance_mode = true;
+
+ let values = {};
+ values["statecode"] = calculateStateCode();
+ values["power_mode"] = "maintenance";
+ let tbname = relaysData[line].tbname;
+ sendTelemetry(values, tbname);
+
+ monitor.info("turnOnLine (line, SETTINGS.maintenance_mode)", line, SETTINGS.maintenance_mode, info);
+
+ return;
+ }
+
+ if( pin === undefined) pin = getPin(line);
+
+ monitor.info("turnOnLine (line, pin, force)", line, pin, force, info);
+
+ if( pin === undefined)
+ {
+ monitor.info("pin is undefined!", line);
+ return;
+ }
+
+
+ if(!force)
+ {
+ if(relaysData[line].contactor == 1)
+ {
+ instance.send(SEND_TO.debug, "line is already on " + line );
+ logger.debug("turnOnLine: line is already on: ", line);
+
+ return;
+ }
+ }
+
+ // if(!rsPort.isOpen && !ws)
+ if(!rsPort && !ws)
+ {
+ errLogger.error("di do controller - port or websocket is not opened");
+ return;
+ }
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( pin );
+ arr.push( 0 );
+ arr.push( 1 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ if(err === undefined)
+ {
+ console.log("turnONLine zapisal do rsPortu", line, arr);
+ switchLogic(arr);
+ }
+ else
+ {
+ monitor.info("turnOnLine WRITE error", err);
+ }
+
+ });
+
+ }
+ else if(ws)
+ {
+ console.log("turnONLine pin (relay)", pin);
+ //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
+ ws.send(JSON.stringify(cmd));
+ switchLogic(pin, 1)
+ }
+ }
+
+
+ function turnOffLine(line, pin, force, info)
+ {
+ if(force == undefined) force = false;
+
+ if(line == 0)
+ {
+ SETTINGS.maintenance_mode = false;
+
+ let values = {};
+ values["statecode"] = calculateStateCode();
+ values["power_mode"] = "Automatic";
+ sendTelemetry(values, rvoTbName);
+
+ return;
+ }
+
+ if(pin === undefined) pin = getPin(line);
+
+ monitor.info("turnOffLine (line, pin, force)", line, pin, force, info);
+
+ if(pin === undefined)
+ {
+ errLogger.error("pin is undefined!", line);
+ return;
+ }
+
+ if(!force)
+ {
+ if(relaysData[line].contactor == 0)
+ {
+ instance.send(SEND_TO.debug, "line is already off " + line );
+ logger.debug("turnOffLine: line already off:", line);
+
+ return;
+ }
+ }
+
+ // if(!rsPort.isOpen && !ws)
+ if(!rsPort && !ws)
+ {
+ errLogger.error("dido controller - port or websocket is not opened");
+ return;
+ }
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( pin );
+ arr.push( 0 );
+ arr.push( 0 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ if(err === undefined)
+ {
+ console.log("turnOffLine zapisal do rsPort-u", line, arr);
+ switchLogic(arr);
+ }
+ else
+ {
+ monitor.info("turnOffLine WRITE error", err);
+ }
+
+ });
+
+ }
+ else if(ws)
+ {
+ //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
+ monitor.info("turnOffLine pin (relay)", pin);
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0};
+ ws.send(JSON.stringify(cmd));
+ switchLogic(pin, 0)
+ }
+
+ }
+
+
+ // main opening
+ instance.on("1", flowdata => {
+ main();
+ })
+
+
+ // we expect array as flowdata.data
+ instance.on("0", (flowdata) => {
+
+ console.log(flowdata.data);
+
+ if(flowdata.data instanceof Object)
+ {
+
+ if(flowdata.data.hasOwnProperty("sender"))
+ {
+ //console.log("sender", flowdata.data);
+
+ if(flowdata.data.sender == "gettemperature")
+ {
+ deviceStatuses["temperature"] = flowdata.data.status;
+ }
+ else if(flowdata.data.sender == "modbus_citysys")
+ {
+ //elektromer rvo
+ if(flowdata.data.tbdata.hasOwnProperty(rvoTbName))
+ {
+ //rvo
+ deviceStatuses["rvo"] = {status: flowdata.data.tbdata[rvoTbName][0]["values"]["status"], tbdata: flowdata.data.tbdata};
+ }
+ else {
+ //posli do tb - to je vyriesene na urovni modbus_citysys
+ //instance.send(SEND_TO.tb, flowdata.data.tbdata);
+ }
+ }
+
+ instance.send(SEND_TO.debug, flowdata.data );
+ return;
+ }
+
+ let obj = flowdata.data;
+
+ let line = obj.line;
+ let force = obj.force;
+ let info = obj.info;
+
+ if(obj.command == "turnOn") turnOnLine(line, undefined, force, info);
+ else if(obj.command == "turnOff") turnOffLine(line, undefined, force, info);
+ else if(obj.command == "turnOnAlarm") turnOnAlarm();
+ else if(obj.command == "turnOffAlarm") turnOffAlarm();
+
+ return;
+ }
+
+ //! ake data prichadzaju z cmd_manager.js ???
+ //TODO transform to websocket
+ if (Array.isArray(flowdata.data)){
+
+ rsPort.write(Buffer.from(flowdata.data), function(err) {
+ switchLogic(flowdata.data);
+
+ instance.send(SEND_TO.debug, {"WRITE":flowdata.data} );
+ });
+ }
+ })
+
+
+ function calculateStateCode()
+ {
+
+ let bytes = [];
+ let bits = [];
+
+
+ //Hlavný istič - state_of_main_switch
+ if(deviceStatuses["state_of_main_switch"] == "On") bits.push(0);
+ else if(deviceStatuses["state_of_main_switch"] == "Off") bits.push(1);
+
+ //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false
+ if(!SETTINGS.maintenance_mode)
+ {
+ if(deviceStatuses["rotary_switch_state"] == "Manual")
+ {
+ bits.push(0);
+ bits.push(1);
+ }
+
+ if(deviceStatuses["rotary_switch_state"] == "Automatic")
+ {
+ bits.push(0);
+ bits.push(0);
+ }
+
+ if(deviceStatuses["rotary_switch_state"] == "Off")
+ {
+ bits.push(1);
+ bits.push(0);
+ }
+ }
+ else{
+ bits.push(1);
+ bits.push(1);
+ }
+
+ //Dverový kontakt
+ if(deviceStatuses["door_condition"] == "closed")
+ {
+ bits.push(0);
+ }
+ else bits.push(1);
+
+ //EM
+ if(deviceStatuses["rvo"].status == "NOK") bits.push(1);
+ else bits.push(0);
+
+ //Teplomer
+ if(deviceStatuses["temperature"] == "NOK") bits.push(1);
+ else bits.push(0);
+
+ //Batéria
+ if(deviceStatuses["battery"] == "NOK") bits.push(1);
+ else bits.push(0);
+
+ //Zdroj
+ if(deviceStatuses["power_supply"] == "NOK") bits.push(1);
+ else bits.push(0);
+
+ //MN
+ if(deviceStatuses["master_node"] == "NOK") bits.push(1);
+ else bits.push(0);
+
+ //výpadok napätia na fáze
+ if(deviceStatuses["no_voltage"] == "NOK") bits.push(1);
+ else bits.push(0);
+
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+
+ //console.log("calculateStateCode - deviceStatuses", deviceStatuses);
+ //console.log("calculateStateCode", bits);
+
+ let byte0 = bitwise.byte.write(bits.slice(0,8).reverse());
+ let byte1 = bitwise.byte.write(bits.slice(8).reverse());
+
+ let byte = bytesToInt([byte1, byte0]);
+
+ //console.log("calculateStateCode", byte);
+
+ return byte;
+ }
+
+
+ function checkFinalRVOStatus() {
+
+ // we check if any of these pins values are 0 --> it means status RVO is "NOK"
+ // pinIndex 6 is door_condition - if open in maintenance mode - status = OK
+
+ //set RVO state
+
+ let status = "OK";
+
+ if(deviceStatuses["rvo"].status == "NOK")
+ {
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: rvo status is NOK");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: rvo status is NOK", deviceStatuses["rvo"].tbdata);
+
+ status = "NOK";
+ }
+
+ //ak teplomer NOK, rvo nok
+ if(deviceStatuses["temperature"] == "NOK")
+ {
+
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK");
+
+ status = "NOK";
+ }
+
+ if(status == "OK")
+ {
+ for (const pinIndex of [1, 4, 6]) {
+ if (previousValues[pinIndex] === 0) {
+
+ if (pinIndex === 6 && SETTINGS.maintenance_mode) continue;
+
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type);
+
+ status = "NOK";
+
+ break;
+ }
+ }
+ }
+
+ // battery status. If value is 1 - battery is not ok
+ if (previousValues[5] === 1)
+ {
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery");
+
+ status = "NOK";
+ }
+
+ //ak mame telemetriu z elektromeru, posleme
+ if(deviceStatuses["rvo"].tbdata != undefined)
+ {
+ //deviceStatuses["rvo"] = {status: flowdata.data.tbdata[rvoTbName][0]["values"]["status"], tbdata: flowdata.data.tbdata};
+
+ deviceStatuses["rvo"].tbdata[rvoTbName][0]["values"]["status"] = status;
+
+
+ instance.send(SEND_TO.tb, deviceStatuses["rvo"].tbdata);
+ delete deviceStatuses["rvo"].tbdata;
+ }
+
+ //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding);
+
+ if(!SETTINGS.masterNodeIsResponding)
+ {
+ //errLogger.error("Master node is not responding");
+ errorHandler.sendMessageToService("Master node is not responding");
+ status = "NOK";
+
+ deviceStatuses["master_node"] = "NOK";
+ }
+ else deviceStatuses["master_node"] = "OK";
+
+ //console.log("checkFinalRVOStatus", status);
+ if(SETTINGS.no_voltage.size > 0)
+ {
+ let writeToFile = errorHandler.processMessage("no voltage detected");
+ if(writeToFile) errLogger.error("no voltage detected", SETTINGS.no_voltage);
+
+ status = "NOK";
+
+ deviceStatuses["no_voltage"] = "NOK";
+ }
+ else deviceStatuses["no_voltage"] = "OK";
+
+ if(status == "NOK")
+ {
+ sendTelemetry({status: "NOK"}, rvoTbName);
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ // we pass array to function in case of rsPort [[55,3,0,1]]
+ // we pass two values in case of websocket [3,1]
+ const switchLogic = (...args) => {
+
+ let values = {status: "OK"};
+ let dataToTb, pinIndex, newPinValue, twighlight;
+
+ if(args.length == 1)
+ {
+ pinIndex = args[0][1] + 1;
+ if (pinIndex === 17) pinIndex--;
+ newPinValue = args[0][3];
+ twighlight = args[0][2];
+ }
+ else
+ {
+ pinIndex = args[0];
+ newPinValue = args[1];
+ }
+
+ let obj = pinsData[pinIndex];
+
+ if(obj == undefined)
+ {
+ previousValues[pinIndex] = newPinValue;
+ return;
+ }
+
+ let type = obj.type;
+ let line = obj.line;
+ let tbname = obj.tbname;
+
+ //default value
+ let value = "On";
+ if(newPinValue === 0) value = "Off";
+
+ //Hlavný istič
+ if(type === "state_of_main_switch")
+ {
+ if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+ values["status"] = "NOK";
+
+ deviceStatuses["state_of_main_switch"] = "Off";
+ }
+ else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+
+ deviceStatuses["state_of_main_switch"] = "On";
+ }
+ }
+
+ //Prevádzkový mód
+ else if(type == "rotary_switch_state")
+ {
+ // combination of these two pins required to get result
+ let pin2, pin3;
+ if(pinIndex == 2 || pinIndex == "input1_02")
+ {
+ pin2 = newPinValue;
+ pin3 = previousValues[3] || previousValues["input1_03"];
+
+ if(pin3 == undefined)
+ {
+ previousValues[pinIndex] = newPinValue;
+ return;
+ }
+ }
+ else if(pinIndex == 3 || pinIndex == "input1_03")
+ {
+ pin3 = newPinValue;
+ pin2 = previousValues[2] || previousValues["input1_02"];
+
+ if(pin2 == undefined)
+ {
+ previousValues[pinIndex] = newPinValue;
+ return;
+ }
+ }
+
+ //console.log('***********************', pin2, pin3)
+ if (pin2 == 1 && pin3 == 0) value = "Manual";
+ if (pin2 == 0 && pin3 == 0) value = "Off";
+ if (pin2 == 0 && pin3 == 1) value = "Automatic";
+
+ deviceStatuses["rotary_switch_state"] = value;
+
+ //automatic - profilu pre nody sa vykonavaju
+ //ak je spracovany, a automatic - tak ho zapnem
+ //ak nie je spracovany, iba profil zapisem
+
+ if(pin2 != undefined && pin3 != undefined) instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value});
+
+ //console.log("rotary_switch_state pin", pin2, pin3, value);
+ }
+ //Zdroj - pin 4
+ else if (type === "power_supply")
+ {
+ if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", rvoTbName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
+ values["status"] = "NOK";
+
+ deviceStatuses["power_supply"] = "NOK";
+ }
+ else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", rvoTbName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
+
+ deviceStatuses["power_supply"] = "OK";
+ }
+ }
+ //Batéria - pin 5
+ else if (type === "battery")
+ {
+ if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
+ values["status"] = "NOK";
+
+ deviceStatuses["battery"] = "NOK";
+ }
+ else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", rvoTbName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
+
+ deviceStatuses["battery"] = "OK";
+ }
+ }
+ //Dverový kontakt - pin 6
+ else if(type == "door_condition")
+ {
+ newPinValue === 0 ? value = "open" : value = "closed";
+
+ if (newPinValue != previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", SEND_TO.tb, instance, "rvo_door");
+ //TODO ? sendNotification("switchLogic", rvoTbName, "door_value", {value: value}, "", SEND_TO.tb, instance, "rvo_door");
+ }
+
+ if (value === "open" && SETTINGS.maintenance_mode)
+ {
+ sendNotification("switchLogic", rvoTbName, "door_opened", {}, "", SEND_TO.tb, instance, "rvo_door");
+ }
+
+ if (value === "open" && !SETTINGS.maintenance_mode)
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", rvoTbName, "door_opened_without_permission", {}, "", SEND_TO.tb, instance, "rvo_door");
+ values["status"] = "NOK";
+
+ turnOnAlarm();
+ }
+
+ if (value === "closed")
+ {
+ if(alarmStatus == "ON") turnOffAlarm();
+ //turnOffAlarm();
+
+ sendNotification("switchLogic", rvoTbName, "door_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
+ }
+
+ deviceStatuses["door_condition"] = value;
+
+ }
+ else if(type == "twilight_sensor")
+ {
+ //lux sensor
+ value = parseFloat(newPinValue + (256*twighlight));
+
+ let now = new Date();
+ //new Date(dusk.getTime()
+
+ let obj = {timestamp: now.getTime(), value: value};
+
+ //test
+ //twilight_sensor_interval = 1;
+
+ twilight_sensor.push(obj);
+ twilight_sensor_array.push(value);
+
+ //check if we receive just 1 constant value from lux sensor ==> error
+ if(twilight_sensor_array.length > 10) {
+
+ let set = new Set(twilight_sensor_array);
+ if(set.size === 1 && !twighlightError)
+ {
+ twighlightError = true;
+ values["status"] = "NOK";
+ let value = twilight_sensor_array.shift();
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance );
+ newPinValue = 0;
+ }
+ else if (set.size !== 1 && twighlightError)
+ {
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
+ twighlightError = false;
+ twilight_sensor_array.shift();
+ newPinValue = value;
+ }
+ else if (set.size === 1 && twighlightError)
+ {
+ values["status"] = "NOK";
+ twilight_sensor_array.shift();
+ newPinValue = 0;
+ }
+ }
+
+
+ let diff = twilight_sensor[ twilight_sensor.length - 1 ].timestamp - twilight_sensor[0].timestamp;
+ if(diff >= twilight_sensor_interval * 60 * 1000)
+ {
+ const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length;
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: average});
+
+ twilight_sensor = [];
+
+ //console.log("lux_sensor send", average);
+ }
+ //else console.log("lux_sensor", value, diff);
+
+ values["status"] = "OK";
+
+ //
+ }
+ else if(type == "state_of_contactor")
+ {
+ if(!(deviceStatuses["state_of_contactor"][line] == value))
+ {
+ sendNotification("switchLogic", rvoTbName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
+ }
+
+ deviceStatuses["state_of_contactor"][line] = value;
+
+ //true, false
+ if(value === "On") value = true;
+ else if(value === "Off") value = false;
+
+ //TODO do we need to modify relays table with contactor value, if we do not use it on startup ??
+ let dataChanged = false;
+ if(relaysData[line].contactor !== newPinValue) {
+ dataChanged = true;
+ relaysData[line].contactor = newPinValue;
+ }
+
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged});
+ reportLineStatus(line);
+
+ //modify table relays
+ // dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
+ // builder.callback(function(err, response) {
+
+ // if(err == undefined)
+ // {
+
+ // let time = 0;
+ // if(value) time = 1000 * 10;//10 sekund
+
+ // let dataChanged = false;
+ // if(relaysData[line].contactor != newPinValue) dataChanged = true;
+ // relaysData[line].contactor = newPinValue;
+
+ // //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
+ // //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
+
+ // setTimeout(function(){
+ // instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged});
+ // }, time);
+
+ // reportLineStatus(line);
+ // }
+ // else
+ // {
+ // errLogger.error("modify table relays failed", err);
+ // }
+ // });
+ // });
+ }
+
+ else if(type === "state_of_breaker")
+ {
+
+ let valueChanged = false;
+ if(newPinValue != previousValues[pinIndex]) valueChanged = true;
+
+ if(valueChanged)
+ {
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line});
+ }
+
+ if(value == "Off") values["status"] = "NOK";
+
+ deviceStatuses["state_of_breaker"][line] = value;
+
+ reportLineStatus(line);
+
+ }
+
+ values[type] = value;
+
+ let result = checkFinalRVOStatus();
+ if(!result && line == 0)
+ {
+ values["status"] = "NOK";
+ }
+
+
+ if(pinsData.hasOwnProperty(pinIndex))
+ {
+ let valueChanged = false;
+ if(newPinValue != previousValues[pinIndex]) valueChanged = true;
+
+ if(type == "state_of_contactor") valueChanged = true;
+ if(type == "rotary_switch_state") valueChanged = true;
+ if(type === "state_of_breaker")
+ {
+ //console.log(type, values, valueChanged);
+ }
+
+ if(rvoTbName == "")
+ {
+ console.log("rvoTbName is EMPTY");
+ }
+
+ if(rvoTbName == tbname)
+ {
+ values["statecode"] = calculateStateCode();
+ //console.log(type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname);
+ }
+
+
+ if(valueChanged)
+ {
+ sendTelemetry(values, tbname);
+ }
+
+ if(type == "rotary_switch_state")
+ {
+ if(SETTINGS.maintenance_mode) value = "maintenance";
+ value = value.toLowerCase();
+
+ let values = {};
+ values["power_mode"] = value;
+
+ sendTelemetry(values, tbname);
+ }
+ }
+ else
+ {
+ logger.debug("no pinIndex", pinsData[pinIndex], pinsData);
+ }
+
+ //pin was changed
+ previousValues[pinIndex] = newPinValue;
+
+
+ }
+
+ function sendTelemetry(values, tbname)
+ {
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+ }
+
+
+}
+
+
+
+
+//! incomming data to websocket
+// [
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_08',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_01',
+// alias: 'al_lights_kitchen',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_02',
+// alias: 'al_lights_bedroom',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_03',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_04',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_05',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_06',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_07',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_08',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_mode: 'Enabled',
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// dev: 'input',
+// modes: [ 'Simple', 'DirectSwitch' ],
+// debounce: 50,
+// counter: 1,
+// value: 1,
+// alias: 'al_main_switch',
+// mode: 'Simple',
+// circuit: '1_01'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 1,
+// circuit: '1_02',
+// debounce: 50,
+// counter: 2,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 1,
+// circuit: '1_03',
+// debounce: 50,
+// counter: 2,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_04',
+// debounce: 50,
+// counter: 1,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_05',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_06',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_07',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+// {
+// interval: 3,
+// value: 24.5,
+// circuit: '28744F7791180257',
+// address: '28744F7791180257',
+// time: 1631873896.48797,
+// typ: 'DS18B20',
+// lost: false,
+// dev: 'temp'
+// },
+// {
+// bus: '/dev/i2c-2',
+// interval: 3,
+// dev: 'owbus',
+// scan_interval: 300,
+// circuit: '1',
+// do_scan: false,
+// do_reset: false
+// },
+// {
+// glob_dev_id: 1,
+// last_comm: 0.014672994613647461,
+// ver2: '0.1',
+// sn: 42,
+// circuit: '1',
+// model: 'S207',
+// dev: 'neuron',
+// board_count: 1
+// },
+// {
+// circuit: '1_01',
+// value: 0,
+// glob_dev_id: 1,
+// dev: 'wd',
+// timeout: 5000,
+// was_wd_reset: 0,
+// nv_save: 0
+// }
+// ]
+
+//! loaded pins_data --> from LM
+// {
+// '1': { pin: 1, type: 'state_of_main_switch', line: 0 },
+// '2': { pin: 2, type: 'rotary_switch_state', line: 0 },
+// '3': { pin: 3, type: 'rotary_switch_state', line: 0 },
+// '4': { pin: 4, type: 'power_supply', line: 0 },
+// '5': { pin: 5, type: 'battery', line: 0 },
+// '6': { pin: 6, type: 'door_condition', line: 0 },
+// '8': { pin: 8, type: 'state_of_breaker', line: 1 },
+// '9': { pin: 9, type: 'state_of_breaker', line: 2 },
+// '10': { pin: 10, type: 'state_of_breaker', line: 3 },
+// '11': { pin: 11, type: 'state_of_contactor', line: 1 },
+// '12': { pin: 12, type: 'state_of_contactor', line: 2 },
+// '13': { pin: 13, type: 'state_of_contactor', line: 3 },
+// '16': { pin: 16, type: 'twilight_sensor', line: 0 }
+// }
+
+//! pins.table --> from LM
+// pin:number|type:string|line:number
+// *|1|state_of_main_switch|0|...........
+// *|2|rotary_switch_state|0|...........
+// *|3|rotary_switch_state|0|...........
+// *|4|power_supply|0|...........
+// *|5|battery|0|...........
+// *|6|door_condition|0|...........
+// *|8|state_of_breaker|1|...........
+// *|9|state_of_breaker|2|...........
+// *|10|state_of_breaker|3|...........
+// *|11|state_of_contactor|1|...........
+// *|12|state_of_contactor|2|...........
+// *|13|state_of_contactor|3|...........
+// *|16|twilight_sensor|0|...........
+
+//! pins.table --> from UNIPI
+// pin:string|type:string|line:number
+// *|al_mswitch|state_of_main_switch|0|...........
+// *|al_rswitch1|rotary_switch_state|0|...........
+// *|al_rswitch2|rotary_switch_state|0|...........
+// *|al_power|power_supply|0|...........
+// *|al_battery|battery|0|...........
+// *|al_door|door_condition|0|...........
+// *|al_breaker1|state_of_breaker|1|...........
+// *|al_breaker2|state_of_breaker|2|...........
+// *|al_breaker3|state_of_breaker|3|...........
+// *|al_breaker4|state_of_breaker|4|...........
+// *|al_relay_1|state_of_contactor|1|...........
+// *|al_relay_2|state_of_contactor|2|...........
+// *|al_relay_3|state_of_contactor|3|...........
+// *|al_relay_4|state_of_contactor|4|...........
+// *|16|twilight_sensor|0|...........
+// *|28744F7791180257|temperature|0|...........
+
+
+//! pins_data --> from UNIPI
+// {
+// '16': { pin: '16', type: 'twilight_sensor', line: 0 },
+// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 },
+// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 },
+// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 },
+// al_power: { pin: 'al_power', type: 'power_supply', line: 0 },
+// al_battery: { pin: 'al_battery', type: 'battery', line: 0 },
+// al_door: { pin: 'al_door', type: 'door_condition', line: 0 },
+// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 },
+// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 },
+// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 },
+// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 },
+// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 },
+// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 },
+// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 },
+// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 },
+// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', line: 0 }
+// }
+
+
+//! relays_data
+// {
+// '0': {
+// line: 0,
+// tbname: 'KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV',
+// contactor: 1,
+// profile: ''
+// },
+// '1': {
+// line: 1,
+// tbname: 'RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O',
+// contactor: 0,
+// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+// },
+// '2': {
+// line: 2,
+// tbname: 'dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7',
+// contactor: 0,
+// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+// },
+// '3': {
+// line: 3,
+// tbname: 'vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V',
+// contactor: 0,
+// profile: '{"intervals":[{"value":0,"end_time":"20:30","start_time":"13:00"},{"value":1,"end_time":"00:10","start_time":"20:30"},{"value":0,"end_time":"13:00","start_time":"05:40"},{"value":1,"end_time":"05:40","start_time":"00:10"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+// }
+// }
+
diff --git a/flow/dido_controller.js b/flow/dido_controller.js
index b429b14..fe1412b 100644
--- a/flow/dido_controller.js
+++ b/flow/dido_controller.js
@@ -4,9 +4,8 @@ exports.version = '2.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
exports.input = 3;
-exports.output = ["red", "white", "yellow"];
+exports.output = ["red", "white", "yellow", "green"];
exports.click = false;
-exports.author = 'Daniel Segeš';
exports.icon = 'bolt';
exports.options = { edge: "undefined" };
@@ -57,24 +56,30 @@ state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda
momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale tá zmena by sa mala ukázať aj na platforme
*/
+const { errLogger, logger, monitor } = require('./helper/logger');
+const SerialPort = require('serialport');
+const WebSocket = require('ws');
+//const { exec } = require('child_process');
+const { runSyncExec } = require('./helper/serialport_helper');
+const { bytesToInt, resizeArray } = require('./helper/utils');
+const { sendNotification } = require('./helper/notification_reporter');
+const bitwise = require('bitwise');
-//globals
-//FIRMWARE version
-FLOW.OMS_edge_fw_version = "2024-07-08";//rok-mesiac-den
-FLOW.OMS_edgeName = "";
-FLOW.OMS_maintenance_mode = false;
+const DataToTbHandler = require('./helper/DataToTbHandler');
+let tbHandler;
-//dynamic values
-FLOW.OMS_masterNodeIsResponding = true; //cmd_manager
-//FLOW.OMS_brokerready = false //wsmqttpublish
-FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer
+const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
+const errorHandler = new ErrorToServiceHandler();
-//see loadSettings() in cmd_manager
-FLOW.OMS_language = "en";//cmd_manager
-FLOW.OMS_rvo_name = "";//cmd_manager
-FLOW.OMS_rvo_tbname = "";//relaysData
-FLOW.OMS_temperature_adress = "";//cmd_manager
-//-----------------------------------------------
+let ws = null;
+let rsPort = null;
+
+let pinsData;
+let relaysData;
+let rvoTbName;
+let GLOBALS; //FLOW global GLOBALS
+let SETTINGS; // GLOBALS.settings
+let controller_type;
let alarmStatus = "OFF";
@@ -84,43 +89,6 @@ const SEND_TO = {
cmd_manager: 2
}
-var log4js = require("log4js");
-var path = require('path');
-
-log4js.configure({
- appenders: {
- errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
- console: { type: 'console' }
- },
- categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
- }
-});
-
-const errLogger = log4js.getLogger("errLogs");
-const logger = log4js.getLogger();
-const monitor = log4js.getLogger("monitorLogs");
-
-//console.log(path.join(__dirname, 'err.txt', "-----------------------------"));
-
-/*
-process.on('uncaughtException', function (err) {
-
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
-
- //process.exit(1);
-})
-*/
-
-//USAGE
-//logger.debug("text")
-//monitor.info('info');
-//errLogger.error("some error");
exports.install = function(instance) {
@@ -136,17 +104,16 @@ exports.install = function(instance) {
//process.exit(1);
})
- let previousValues = {temperature: 0};
+ let previousValues = {};
let rsPortReceivedData = [];
+ //to be able to get proper twilight values, when
let twilight_sensor_interval = 5;//minutes
let twilight_sensor = [];
const twilight_sensor_array = [];
let twilightError = false;
- let edgeName = "";
-
- monitor.info("DI_DO_Relay_Controller installed");
+ monitor.info("DIDO_Relay_Controller installed");
//key is PIN number , line: 0 = RVO
/*
@@ -167,67 +134,38 @@ exports.install = function(instance) {
};
*/
- const dbPins = TABLE("pins");
- let pinsData = {};//key is pin
-
- const dbRelays = TABLE("relays");
- let relaysData = {};//key is line
-
//status for calculating Statecodes
- let deviceStatuses = {};//key is device name: temperature,....
- deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič
- deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód
- deviceStatuses["door_condition"] = "closed";//Dverový kontakt
- deviceStatuses["em"] = "OK";//elektromer rvo
- deviceStatuses["temperature"] = "OK";//templomer
- deviceStatuses["battery"] = "OK";//Batéria
- deviceStatuses["power_supply"] = "OK";//Zdroj
- deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding
- deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze
+ let deviceStatus = { //key is device name: temperature,....
+ "state_of_main_switch": "Off", //Hlavný istič
+ "rotary_switch_state": "Off", //Prevádzkový mód
+ "door_condition": "closed", //Dverový kontakt
+ "em": "OK", //elektromer rvo
+ "temperature": "OK", //templomer
+ "battery": "OK", //Batéria
+ "power_supply": "OK", //Zdroj
+ "master_node": "OK", //MN - GLOBALS.settings.masterNodeIsResponding
+ "no_voltage": "OK", //GLOBALS.settings.no_voltage - výpadok napätia na fáze
+ "state_of_breaker": {}, //"Off",//Istič
+ "state_of_contactor": {}, //"Off",//Stykač
+ "twilight_sensor": "OK" //lux sensor
+ };
- deviceStatuses["state_of_breaker"] = {};//"Off";//Istič
- deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač
- deviceStatuses["twilight_sensor"] = "OK"; //lux sensor
- /*
- dbRelays.on('change', function(doc, old) {
- console.log("'DI_DO_Controller - dbRelays.on('change'");
- instance.send(SEND_TO.cmd_manager, "reload_relays");
- });
- */
+ function main() {
- const SerialPort = require('serialport');
- const WebSocket = require('ws');
+ GLOBALS = FLOW.GLOBALS;
+ SETTINGS = FLOW.GLOBALS.settings;
+ rvoTbName = SETTINGS.rvoTbName;
+ pinsData = GLOBALS.pinsData;
+ relaysData = GLOBALS.relaysData;
- let ws = null;
- let rsPort = null;
-
- //const { exec } = require('child_process');
- const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js');
- const { bytesToInt, resizeArray } = require('./helper/utils');
- const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
- const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js');
- const bitwise = require('bitwise');
+ tbHandler = new DataToTbHandler(SEND_TO.tb)
+ tbHandler.setSender(exports.title);
- const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
- const errorHandler = new ErrorToServiceHandler();
+ controller_type = SETTINGS.controller_type //"lm" or "unipi" //logicMachine
+ if(controller_type == "") controller_type = "lm";
- //let useTurnOffCounter = false;
- //let turnOffCounter = 0;
- let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine
- if(controller_type == "") controller_type = "lm";
-
- console.log(exports.title, "controller type: ", controller_type);
-
- async function loadAllDb()
- {
- let responsePins = await promisifyBuilder(dbPins.find());
- pinsData = makeMapFromDbResult(responsePins, "pin");
-
- let responseRelays = await promisifyBuilder(dbRelays.find());
- relaysData = makeMapFromDbResult(responseRelays, "line");
-
- FLOW.OMS_rvo_tbname = relaysData[0].tbname;
+ console.log(exports.title, "controller type: ", controller_type);
if(controller_type === "lm")
{
@@ -240,12 +178,13 @@ exports.install = function(instance) {
else {
errLogger.debug("UNKNOWN controller_type:", controller_type);
}
- }
+ }
function initialSetting()
{
- //force turn off relays & set tbname
+ //force turn off relays
+
let keys = Object.keys(pinsData);
for(let i = 0; i < keys.length; i++)
{
@@ -257,15 +196,12 @@ exports.install = function(instance) {
if(relaysData[line] != undefined)
{
pinsData[key].tbname = relaysData[line].tbname;
-
- relaysData[line].contactor = 0;
+ //relaysData[line].contactor = 0;
}
else
{
errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line);
-
- //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null );
- sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
+ sendNotification("set port ", rvoTbName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
}
}
@@ -276,37 +212,23 @@ exports.install = function(instance) {
//this will modify database
let forceTurnOff = true;
- turnOffLine(line, pin, forceTurnOff, "turn off on startup");
+ turnLine("off", line, pin, forceTurnOff, "turn off on startup");
}
}
//report RVO version relaysData[0].tbname;
let values = {};
- values["edge_fw_version"] = FLOW.OMS_edge_fw_version;
- values["maintenance_mode"] = FLOW.OMS_maintenance_mode;
- values["status"] = "OK";
+ values["edge_fw_version"] = SETTINGS.edge_fw_version;
+ values["maintenance_mode"] = SETTINGS.maintenance_mode;
- edgeName = relaysData[0].tbname;
- FLOW.OMS_edgeName = edgeName;
+ sendTelemetry(values, rvoTbName);
- dataToTb = {
- [edgeName]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- instance.send(SEND_TO.tb, dataToTb);
-
- let time = 3*1000;
+ let time = 5*1000;
setTimeout(function(){
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"});
- sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", SEND_TO.tb, instance );
- monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version);
-
+ sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
+ monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
}, time);
}
@@ -331,27 +253,23 @@ exports.install = function(instance) {
//set port
rsPort.write(Buffer.from(setRSPortData), function(err) {
- monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
+ if(!err) {
+ monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
- turnOffAlarm();
-
- //useTurnOffCounter = true;
- //turnOffCounter = relaysData.length - 1;
-
- initialSetting();
+ turnAlarm("off");
+ initialSetting();
+ }
})
- }).catch(function (reason) {
- //instance.send(SEND_TO.debug, exports.title + " runSyncExec - promise rejected:" + reason);
- errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason);
-
- errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason);
+ }).catch(function(reason) {
+ errLogger.error(exports.title + " runSyncExec - promise rejected:" + reason);
+ errorHandler.sendMessageToService(exports.title + " runSyncExec - promise rejected:" + reason);
});
});
- rsPort.on('data', function (data){
+ rsPort.on('data', function(data) {
rsPortReceivedData = [...rsPortReceivedData, ...data];
@@ -394,7 +312,6 @@ exports.install = function(instance) {
})
rsPort.open();
-
}
@@ -409,7 +326,7 @@ exports.install = function(instance) {
ws.onopen = function open() {
instance.send(0, exports.title + " running");
- turnOffAlarm();
+ turnAlarm("off");
// useTurnOffCounter = true;
// turnOffCounter = relaysData.length - 1;
@@ -425,6 +342,7 @@ exports.install = function(instance) {
}, 150000)
};
+
// SAMPLE DATA FROM WEBSOCKET
// {
// glob_dev_id: 1,
@@ -448,44 +366,24 @@ exports.install = function(instance) {
// dev: 'input',
// mode: 'Simple'
// },
- ws.onmessage = function(data) {
+ ws.onmessage = async function(data) {
data = JSON.parse(data.data);
// data comes in array except of "temperature" ==> it comes as an object
- if(!Array.isArray(data))
- {
- let value = data['value'];
-
- // temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB
- if(Math.abs(previousValues["temperature"] - value) > 0.21 )
- {
- const dataToTb = {
- [FLOW.OMS_rvo_tbname]: [
- {
- "ts": Date.now(),
- "values": {temperature: value}
- }
- ]
- };
-
- deviceStatuses["temperature"] = "OK";
- previousValues["temperature"] = value;
- instance.send(SEND_TO.tb, dataToTb);
- }
- return;
- }
+ // we do not handle temperature from evok any more => we return, if temperature comes:
+ if(isObject(data)) return;
data.map(item => {
-
+
let value = item['value'];
let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01"
- if (pin == undefined) return;
+ if(pin == undefined) return;
switchLogic(pin, value);
})
}
-
+
ws.on('error', (err) => {
monitor.info('websocket error, reconnect')
@@ -507,92 +405,59 @@ exports.install = function(instance) {
}
}
- // ! do we need requests every minute ???
- // const startRequests = () => {
- // console.log("startRequest function called");
- // start = setInterval(() => {
- // // console.log("data from evok requested");
- // ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"}));
- // // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]}));
- // }, 150000)
- // }
-
-
instance.on("close", () => {
if(rsPort) rsPort.close();
if(ws) ws.close();
- clearInterval(sendRebuildTasksAt11);
})
- loadAllDb();
function getPin(line)
{
- //conversionTable
- let keys = Object.keys(pinsData);
- for(let i = 0; i < keys.length; i++)
+ //conversionTable
+ let keys = Object.keys(pinsData);
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+
+ if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line)
{
- let key = keys[i];
-
- if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line)
- {
- if(rsPort) return key - 1;
- if(ws) return key;
- }
+ if(rsPort) return key - 1;
+ if(ws) return key;
}
+ }
- logger.debug("no pin detected");
+ logger.debug("no pin detected");
- return null;
+ return null;
}
- function turnOnAlarm()
+ function turnAlarm(onOrOff)
{
- if(FLOW.OMS_maintenance_mode) return;
+ let value = 0;
+ if(onOrOff == "on") value = 1;
- alarmStatus = "ON";
+ if(value == 1 && SETTINGS.maintenance_mode) return;
- if(rsPort)
- {
- let arr = [0x55];
- arr.push( 13 );
- arr.push( 0 );
- arr.push( 1 );
-
- rsPort.write(Buffer.from(arr), function(err) {
- logger.debug("sirena zapnuta");
- });
- }
- else if(ws)
- {
- let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1};
- ws.send(JSON.stringify(cmd));
- logger.debug("sirena zapnuta");
- }
- }
-
-
- function turnOffAlarm()
- {
alarmStatus = "OFF";
+ if(value == 1) alarmStatus = "ON";
if(rsPort)
{
let arr = [0x55];
- arr.push( 13 );
- arr.push( 0 );
- arr.push( 0 );
-
+ arr.push(13);
+ arr.push(0);
+ arr.push(value);
+
rsPort.write(Buffer.from(arr), function(err) {
- logger.debug("sirena vypnuta");
+ logger.debug(`sirena - ${onOrOff}`);
});
}
else if(ws)
{
- let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0};
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": value};
ws.send(JSON.stringify(cmd));
- logger.debug("sirena vypnuta");
+ logger.debug(`sirena - ${onOrOff}`);
}
}
@@ -600,18 +465,16 @@ exports.install = function(instance) {
function reportLineStatus(line)
{
//Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false).
-
let tbname = relaysData[line].tbname;
-
let bits = [];
- if(deviceStatuses["state_of_breaker"][line] == "On")
+ if(deviceStatus["state_of_breaker"][line] == "On")
{
bits.push(0);
}
else bits.push(1);
- if(deviceStatuses["state_of_contactor"][line] == "On")
+ if(deviceStatus["state_of_contactor"][line] == "On")
{
bits.push(0);
}
@@ -622,66 +485,47 @@ exports.install = function(instance) {
let byte = bitwise.byte.write(bits.reverse());
//console.log("line", line, bits, byte);
-
- let values = {
- statecode: byte
- }
-
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
-
- //console.log(values);
-
- instance.send(SEND_TO.tb, dataToTb);
+ sendTelemetry({statecode: byte}, tbname);
}
- function turnOnLine(line, pin, force, info)
+ // turn line on or off
+ function turnLine(onOrOff, line, pin, force, info)
{
-
- instance.send(SEND_TO.debug, "turn on line " + line );
+ //onOrOff => "on" or "off"
+ let value = 0;
+ if(onOrOff == "on") value = 1;
+
if(force == undefined) force = false;
if(line == 0)
{
- if(alarmStatus == "ON") turnOffAlarm();
- FLOW.OMS_maintenance_mode = true;
+ if(value == 1 && alarmStatus == "ON") turnAlarm("off");
+ SETTINGS.maintenance_mode = value? true: false;
let values = {};
values["statecode"] = calculateStateCode();
- values["power_mode"] = "maintenance";
- let tbname = relaysData[line].tbname;
- sendTelemetry(values, tbname);
-
- monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info);
-
- return;
- }
-
- if( pin === undefined) pin = getPin(line);
-
- monitor.info("turnOnLine (line, pin, force)", line, pin, force, info);
-
- if( pin === undefined)
- {
- monitor.info("pin is undefined!", line);
- return;
- }
-
+ values["power_mode"] = value ? "maintenance": "Automatic";
+ sendTelemetry(values, rvoTbName);
+ monitor.info(`turnLine ${onOrOff} - (line, SETTINGS.maintenance_mode)`, line, SETTINGS.maintenance_mode, info);
+ return;
+ }
+
+ if(pin === undefined) pin = getPin(line);
+
+ if(pin === undefined)
+ {
+ errLogger.error("pin is undefined!", line);
+ return;
+ }
+
if(!force)
{
- if(relaysData[line].contactor == 1)
+ if(relaysData[line].contactor == value)
{
- instance.send(SEND_TO.debug, "line is already on " + line );
- logger.debug("turnOnLine: line is already on: ", line);
-
+ instance.send(SEND_TO.debug, `line is already ${onOrOff} ` + line );
+ logger.debug(`turnLine: line is already ${onOrOff} `, line);
return;
}
}
@@ -692,170 +536,94 @@ exports.install = function(instance) {
errLogger.error("dido controller - port or websocket is not opened");
return;
}
-
- if(rsPort)
- {
- let arr = [0x55];
- arr.push( pin );
- arr.push( 0 );
- arr.push( 1 );
-
- rsPort.write(Buffer.from(arr), function(err) {
- if(err === undefined)
- {
- console.log("turnONLine zapisal do rsPortu", line, arr);
- switchLogic(arr);
- }
- else
- {
- monitor.info("turnOnLine WRITE error", err);
- }
-
- });
-
- }
- else if(ws)
- {
- console.log("turnONLine pin (relay)", pin);
- //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
- let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
- ws.send(JSON.stringify(cmd));
- //switchLogic(pin, 1)
- }
- }
-
-
- function turnOffLine(line, pin, force, info)
- {
- if(force == undefined) force = false;
-
- if(line == 0)
- {
- FLOW.OMS_maintenance_mode = false;
-
- let values = {};
- values["statecode"] = calculateStateCode();
- values["power_mode"] = "automatic";
- let tbname = relaysData[line].tbname;
- sendTelemetry(values, tbname);
-
- return;
- }
-
- if( pin === undefined) pin = getPin(line);
-
- monitor.info("turnOffLine (line, pin, force)", line, pin, force, info);
-
- if( pin === undefined)
- {
- errLogger.error("pin is undefined!", line);
- return;
- }
-
- if(!force)
- {
- if(relaysData[line].contactor == 0)
- {
- instance.send(SEND_TO.debug, "line is already off " + line );
- logger.debug("turnOffLine: line already off:", line);
-
- return;
- }
- }
-
- // if(!rsPort.isOpen && !ws)
- if(!rsPort && !ws)
- {
- errLogger.error("di do controller - port or websocket is not opened");
- return;
- }
if(rsPort)
{
let arr = [0x55];
- arr.push( pin );
- arr.push( 0 );
- arr.push( 0 );
+ arr.push(pin);
+ arr.push(0);
+ arr.push(value);
rsPort.write(Buffer.from(arr), function(err) {
if(err === undefined)
{
- console.log("turnOffLine zapisal do rsPort-u", line, arr);
+ monitor.info(`turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
switchLogic(arr);
}
else
{
- monitor.info("turnOffLine WRITE error", err);
- }
-
+ monitor.info(`turnLine ${onOrOff} WRITE error`, err);
+ }
});
}
else if(ws)
{
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
- //monitor.info("turnOffLine pin (relay)", pin);
- let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0};
+ monitor.info(`turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": value};
ws.send(JSON.stringify(cmd));
- //switchLogic(pin, 0)
+ switchLogic(pin, value)
}
-
}
+ // main opening
+ instance.on("2", _ => {
+ main();
+ })
+
+
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device
instance.on("0", flowdata => {
- if(!flowdata.data instanceof Object) return;
+ if(!isObject(flowdata.data)) return;
// console.log('***********************', flowdata.data)
instance.send(SEND_TO.debug, flowdata.data);
// we handle nok status from modbus_reader component and thermometer
- if(flowdata.data?.status)
+ if("status" in flowdata.data)
{
const status = flowdata.data.status;
if(status == "NOK-twilight_sensor")
{
- deviceStatuses["twilight_sensor"] = "NOK";
+ deviceStatus["twilight_sensor"] = "NOK";
}
else if(status == "NOK-em340" || status == "NOK-em111")
{
- deviceStatuses["em"] = "NOK";
+ deviceStatus["em"] = "NOK";
}
else if(status == "NOK-thermometer")
{
- deviceStatuses["temperature"] = "NOK";
+ deviceStatus["temperature"] = "NOK";
}
}
- else if(flowdata.data?.values)
+ else if("values" in flowdata.data)
{
const values = flowdata.data.values;
if(values.hasOwnProperty("twilight_sensor"))
{
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"]});
- deviceStatuses["twilight_sensor"] = "OK"
+ deviceStatus["twilight_sensor"] = "OK"
}
else if(values.hasOwnProperty("temperature"))
{
- deviceStatuses["temperature"] = "OK";
+ deviceStatus["temperature"] = "OK";
}
// EM
else if(values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current"))
{
- deviceStatuses["em"] = "OK";
- }
- else
- {
- return;
+ deviceStatus["em"] = "OK";
+ SETTINGS.no_voltage.size > 0 ? deviceStatus["no_voltage"] = "NOK": deviceStatus["no_voltage"] = "OK";
}
- const updateStatus = checkFinalRVOStatus();
- if(updateStatus) values.status = "OK";
-
- sendTelemetry(values, FLOW.OMS_rvo_tbname);
+ sendTelemetry(values, rvoTbName);
}
+ console.log("-----from data")
+ console.log(flowdata.data)
+ sendRvoStatus();
})
@@ -871,11 +639,10 @@ exports.install = function(instance) {
let force = obj.force;
let info = obj.info;
- if(obj.command == "turnOn") turnOnLine(line, undefined, force, info);
- else if(obj.command == "turnOff") turnOffLine(line, undefined, force, info);
- else if(obj.command == "turnOnAlarm") turnOnAlarm();
- else if(obj.command == "turnOffAlarm") turnOffAlarm();
-
+ if(obj.command == "on") turnLine("on", line, undefined, force, info);
+ else if(obj.command == "off") turnLine("off", line, undefined, force, info);
+ else if(obj.command == "turnOnAlarm") turnAlarm("on");
+ else if(obj.command == "turnOffAlarm") turnAlarm("off");
//! ake data prichadzaju z cmd_manager.js ???
//TODO transform to websocket
@@ -893,35 +660,34 @@ exports.install = function(instance) {
function calculateStateCode()
{
- let bytes = [];
let bits = [];
- //Hlavný istič - state_of_main_switch
- if(deviceStatuses["state_of_main_switch"] == "On")
+ //Hlavný istič - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
+ if(deviceStatus["state_of_main_switch"] == "closed")
{
bits.push(0);
}
- else if(deviceStatuses["state_of_main_switch"] == "Off")
+ else
{
bits.push(1);
}
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
- if(!FLOW.OMS_maintenance_mode)
+ if(!SETTINGS.maintenance_mode)
{
- if(deviceStatuses["rotary_switch_state"] == "Manual")
+ if(deviceStatus["rotary_switch_state"] == "Manual")
{
bits.push(0);
bits.push(1);
}
- if(deviceStatuses["rotary_switch_state"] == "Automatic")
+ if(deviceStatus["rotary_switch_state"] == "Automatic")
{
bits.push(0);
bits.push(0);
}
- if(deviceStatuses["rotary_switch_state"] == "Off")
+ if(deviceStatus["rotary_switch_state"] == "Off")
{
bits.push(1);
bits.push(0);
@@ -933,7 +699,7 @@ exports.install = function(instance) {
}
//Dverový kontakt
- if(deviceStatuses["door_condition"] == "closed")
+ if(deviceStatus["door_condition"] == "closed")
{
bits.push(0);
}
@@ -943,7 +709,7 @@ exports.install = function(instance) {
}
//EM
- if(deviceStatuses["em"] == "NOK")
+ if(deviceStatus["em"] == "NOK")
{
bits.push(1);
}
@@ -953,7 +719,7 @@ exports.install = function(instance) {
}
//Teplomer
- if(deviceStatuses["temperature"] == "NOK")
+ if(deviceStatus["temperature"] == "NOK")
{
bits.push(1);
}
@@ -963,7 +729,7 @@ exports.install = function(instance) {
}
//Batéria
- if(deviceStatuses["battery"] == "NOK")
+ if(deviceStatus["battery"] == "NOK")
{
bits.push(1);
}
@@ -973,7 +739,7 @@ exports.install = function(instance) {
}
//Zdroj
- if(deviceStatuses["power_supply"] == "NOK")
+ if(deviceStatus["power_supply"] == "NOK")
{
bits.push(1);
}
@@ -983,7 +749,7 @@ exports.install = function(instance) {
}
//MN
- if(deviceStatuses["master_node"] == "NOK")
+ if(deviceStatus["master_node"] == "NOK")
{
bits.push(1);
}
@@ -993,7 +759,7 @@ exports.install = function(instance) {
}
//výpadok napätia na fáze
- if(deviceStatuses["no_voltage"] == "NOK")
+ if(deviceStatus["no_voltage"] == "NOK")
{
bits.push(1);
}
@@ -1002,7 +768,7 @@ exports.install = function(instance) {
bits.push(0);
}
- if(deviceStatuses["twilight_sensor"] == "NOK")
+ if(deviceStatus["twilight_sensor"] == "NOK")
{
bits.push(1);
}
@@ -1017,7 +783,7 @@ exports.install = function(instance) {
bits.push(0);
}
- // console.log("calculateStateCode - deviceStatuses", deviceStatuses);
+ // console.log("calculateStateCode - deviceStatus", deviceStatus);
// console.log("calculateStateCode", bits);
let byte0 = bitwise.byte.write(bits.slice(0,8).reverse());
@@ -1026,109 +792,73 @@ exports.install = function(instance) {
let byte = bytesToInt([byte1, byte0]);
//console.log("calculateStateCode -------------------", byte);
-
+
return byte;
}
- function checkFinalRVOStatus() {
+ async function sendRvoStatus() {
+
+ if(!FLOW.dbLoaded) return;
+ //if(SETTINGS === undefined) return;
+
+ const table = {
+ "OK": 1,
+ "NOK": 0
+ };
+
+ const dataToTb = {
+ "electrometer_status": table[deviceStatus["em"]],
+ "twilight_sensor_status": table[deviceStatus["twilight_sensor"]],
+ "thermometer_status": table[deviceStatus["temperature"]],
+ "phase_1_status": 1,
+ "phase_2_status": 1,
+ "phase_3_status": 1,
+ "master_node_status": table[deviceStatus["master_node"]]
+ };
+
+ for (const phase of SETTINGS.no_voltage) dataToTb[`phase_${phase}_status`] = 0;
+
+ dataToTb["status"] = checkRvoStatus();
+ dataToTb["statecode"] = calculateStateCode();
+
+ console.log(dataToTb);
+ sendTelemetry(dataToTb, rvoTbName);
+ }
+
+
+ function checkRvoStatus() {
// we check if any of these pins values are 0 --> it means status RVO is "NOK"
- // pinIndex 6 is door_condition - if open in maintenance mode - status = OK
-
+ // pinIndex 6 is door_condition - if it is opened in maintenance mode - status = OK
//set RVO state
-
let status = "OK";
- if(deviceStatuses["em"] == "NOK")
- {
- let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: EM status is NOK");
- if(writeToFile) errLogger.error("checkFinalRVOStatus: EM status is NOK");
-
- status = "NOK";
+ for (const [key, value] of Object.entries(deviceStatus)) {
+ if(["em", "twilight_sensor", "temperature"].includes(key) && value == "NOK") status = "NOK";
}
- if(deviceStatuses["twilight_sensor"] == "NOK")
- {
- let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: twilight_sensor is NOK");
- if(writeToFile) errLogger.error("checkFinalRVOStatus: twilight sensor is NOK");
-
- status = "NOK";
- }
-
- //ak teplomer NOK, rvo nok
- if(deviceStatuses["temperature"] == "NOK")
- {
-
- let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK");
- if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK");
-
- status = "NOK";
- }
-
if(status == "OK")
{
let pinIndexes = [1, 4, 6];
if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
- //console.log('-------- previousValues', previousValues);
-
for (const pinIndex of pinIndexes) {
if (previousValues[pinIndex] === 0) {
-
- if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue;
-
- let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0");
- if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type);
-
+ if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && SETTINGS.maintenance_mode) continue;
status = "NOK";
-
break;
}
}
}
// battery status. If value is 1 - battery is NOK
- if (previousValues[5] === 1)
- {
- let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery");
- if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery");
+ if (previousValues[5] === 1) status = "NOK";
+ if(!SETTINGS.masterNodeIsResponding) status = "NOK";
+ if(SETTINGS.no_voltage.size > 0) status = "NOK";
- status = "NOK";
- }
-
- //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding);
-
- if(!FLOW.OMS_masterNodeIsResponding)
- {
- //errLogger.error("Master node is not responding");
- errorHandler.sendMessageToService("Master node is not responding");
- status = "NOK";
-
- deviceStatuses["master_node"] = "NOK";
- }
- else deviceStatuses["master_node"] = "OK";
-
- //console.log("checkFinalRVOStatus", status);
- if(FLOW.OMS_no_voltage.size > 0)
- {
- let writeToFile = errorHandler.processMessage("no voltage detected");
- if(writeToFile) errLogger.error("no voltage detected", FLOW.OMS_no_voltage);
-
- status = "NOK";
-
- deviceStatuses["no_voltage"] = "NOK";
- }
- else deviceStatuses["no_voltage"] = "OK";
-
- if(status == "NOK")
- {
- sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname);
-
- return false;
- }
-
- return true;
+ console.log("rvo status",status)
+ return status;
}
@@ -1136,8 +866,8 @@ exports.install = function(instance) {
// we pass two values in case of websocket ==> switchLogic("relay1_03",1) ==> ["relay1_03",1]
const switchLogic = (...args) => {
- let values = {status: "OK"};
- let dataToTb, pinIndex, newPinValue, twilight;
+ let values = {};
+ let pinIndex, newPinValue, twilight;
//data from rsPort
if(args.length == 1)
@@ -1155,13 +885,14 @@ exports.install = function(instance) {
}
let obj = pinsData[pinIndex];
-
if(obj == undefined)
{
previousValues[pinIndex] = newPinValue;
+ //logger.debug("dido-switchLogic ==> no pinIndex", pinIndex);
return;
}
+ //tbname is added to pinsData in initialSettings function
let type = obj.type;
let line = obj.line;
let tbname = obj.tbname;
@@ -1173,22 +904,22 @@ exports.install = function(instance) {
//Hlavný istič
//! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri
//! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition'
- if(type === "!!!state_of_main_switch")
- {
- if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
- {
- sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
- values["status"] = "NOK";
+ // if(type === "!!!state_of_main_switch")
+ // {
+ // if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ // {
+ // sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+ // values["status"] = "NOK";
- deviceStatuses["state_of_main_switch"] = "Off";
- }
- else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
- {
- sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+ // deviceStatus["state_of_main_switch"] = "Off";
+ // }
+ // else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ // {
+ // sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
- deviceStatuses["state_of_main_switch"] = "On";
- }
- }
+ // deviceStatus["state_of_main_switch"] = "On";
+ // }
+ // }
//Prevádzkový mód
if(type == "rotary_switch_state")
@@ -1223,54 +954,51 @@ exports.install = function(instance) {
if (pin2 == 0 && pin3 == 0) value = "Off";
if (pin2 == 0 && pin3 == 1) value = "Automatic";
- deviceStatuses["rotary_switch_state"] = value;
+ deviceStatus["rotary_switch_state"] = value;
//automatic - profilu pre nody sa vykonavaju
//ak je spracovany, a automatic - tak ho zapnem
//ak nie je spracovany, iba profil zapisem
-
- instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value});
+
+ if(pin2 != undefined && pin3 != undefined) instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value});
//console.log("rotary_switch_state pin", pin2, pin3, value);
}
+
//Zdroj - pin 4
else if (type === "power_supply")
{
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance);
- sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
- values["status"] = "NOK";
+ sendNotification("switchLogic", rvoTbName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
- deviceStatuses["power_supply"] = "NOK";
+ deviceStatus["power_supply"] = "NOK";
}
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance);
- sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
+ sendNotification("switchLogic", rvoTbName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
- deviceStatuses["power_supply"] = "OK";
+ deviceStatus["power_supply"] = "OK";
}
}
+
//Batéria - pin 5
else if (type === "battery")
{
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance);
- sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
- values["status"] = "NOK";
+ sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
- deviceStatuses["battery"] = "NOK";
+ deviceStatus["battery"] = "NOK";
}
else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance);
- sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
+ sendNotification("switchLogic", rvoTbName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
- deviceStatuses["battery"] = "OK";
+ deviceStatus["battery"] = "OK";
}
}
+
//Dverový kontakt - pin 6
//! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch"
//! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
@@ -1278,48 +1006,35 @@ exports.install = function(instance) {
{
newPinValue === 0 ? value = "open" : value = "closed";
- if (newPinValue != previousValues[pinIndex])
+ if (value === "open" && SETTINGS.maintenance_mode)
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", SEND_TO.tb, instance, "rvo_door");
- //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", SEND_TO.tb, instance, "rvo_door");
+ sendNotification("switchLogic", rvoTbName, "door_opened", {}, "", SEND_TO.tb, instance, "rvo_door");
}
- if (value === "open" && FLOW.OMS_maintenance_mode)
+ if (value === "open" && !SETTINGS.maintenance_mode)
{
- sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", SEND_TO.tb, instance, "rvo_door");
- }
-
- if (value === "open" && !FLOW.OMS_maintenance_mode)
- {
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance);
- sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", SEND_TO.tb, instance, "rvo_door");
- values["status"] = "NOK";
-
- //console.log(door_has_been_open_without_permision_alarm_is_on);
+ sendNotification("switchLogic", rvoTbName, "door_opened_without_permission", {}, "", SEND_TO.tb, instance, "rvo_door");
// zapneme sirenu
// ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
- if(type === "door_condition") turnOnAlarm();
+ if(type === "door_condition") turnAlarm("on");
}
if (value === "closed")
{
- if(alarmStatus == "ON") turnOffAlarm();
- //turnOffAlarm();
-
- sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
+ if(alarmStatus == "ON") turnAlarm("off");
+ sendNotification("switchLogic", rvoTbName, "door_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
}
- deviceStatuses["door_condition"] = value;
-
+ deviceStatus[type] = value;
}
+
//lux sensor
else if(type == "twilight_sensor")
{
- //! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000.
+ //! TODO - to show nok status, if lux value is not changing more then 10 times.
//Daylight is far more than 1000. So most of the day, when it is sunshine comes just value 1000. But lux sensor is not NOK.
//This is not the case in LM. If value from LM is the same 10x, there is 99% possibility, that sensor is NOK.
- values["status"] = "OK";
value = newPinValue;
if(controller_type === 'lm')
@@ -1344,27 +1059,25 @@ exports.install = function(instance) {
if(set.size === 1 && !twilightError)
{
twilightError = true;
- values["status"] = "NOK";
let value = twilight_sensor_array.shift();
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance );
+
newPinValue = 0;
}
else if (set.size !== 1 && twilightError)
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
+ //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
twilightError = false;
twilight_sensor_array.shift();
+
newPinValue = value;
}
else if (set.size === 1 && twilightError)
{
- values["status"] = "NOK";
twilight_sensor_array.shift();
newPinValue = 0;
}
}
-
let diff = twilight_sensor[ twilight_sensor.length - 1 ].timestamp - twilight_sensor[0].timestamp;
if(diff >= twilight_sensor_interval * 60 * 1000)
{
@@ -1378,72 +1091,60 @@ exports.install = function(instance) {
//else console.log("lux_sensor", value, diff);
}
}
+
else if(type == "state_of_contactor")
{
- //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", SEND_TO.tb, instance );
-
- if(!(deviceStatuses["state_of_contactor"][line] == value))
+ if(!(deviceStatus["state_of_contactor"][line] == value))
{
- sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
+ sendNotification("switchLogic", rvoTbName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
}
- else
- {
- deviceStatuses["state_of_contactor"][line] = value;
- }
+
+ deviceStatus["state_of_contactor"][line] = value;
//true, false
if(value === "On") value = true;
- else if(value === "Off") value = false;
+ else if(value === "Off") value = false;
+
+ //TODO do we need to modify relays table with contactor value, if we do not use it on startup ??
+ let dataChanged = false;
+ if(relaysData[line].contactor !== newPinValue) {
+ dataChanged = true;
+ relaysData[line].contactor = newPinValue;
+ }
+
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged});
+ reportLineStatus(line);
//modify table relays
- dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
+ // dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
+ // builder.callback(function(err, response) {
+ // if(!err)
+ // {
+ // let time = 0;
+ // if(value) time = 1000 * 10;//10 sekund
- builder.callback(function(err, response) {
+ // let dataChanged = false;
+ // if(relaysData[line].contactor != newPinValue) dataChanged = true;
+ // relaysData[line].contactor = newPinValue; // 0,1
- /*
- if(useTurnOffCounter)
- {
- turnOffCounter--;
+ // //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
+ // //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
+ // setTimeout(function(){
+ // instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
+ // }, time);
- if(turnOffCounter <= 0)
- {
- useTurnOffCounter = false;
- }
- }
- */
-
- if(err == undefined)
- {
+ // reportLineStatus(line);
+ // }
+ // else
+ // {
+ // errLogger.error("modify table relays failed", err);
+ // }
- let time = 0;
- if(value) time = 1000 * 10;//10 sekund
-
- let dataChanged = false;
- if(relaysData[line].contactor != value) dataChanged = true;
- relaysData[line].contactor = value;
-
- //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
- //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
-
- setTimeout(function(){
- instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
- }, time);
-
- reportLineStatus(line);
-
-
- }
- else
- {
- errLogger.error("modify table relays failed", err);
- }
-
-
- });
- });
+ // });
+ // });
}
- if(type === "state_of_breaker")
+ else if(type === "state_of_breaker")
{
let valueChanged = false;
@@ -1467,7 +1168,7 @@ exports.install = function(instance) {
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i]});
- deviceStatuses["state_of_breaker"][lineOnSameBraker[i]] = value;
+ deviceStatus["state_of_breaker"][lineOnSameBraker[i]] = value;
reportLineStatus(lineOnSameBraker[i]);
values[type] = value;
@@ -1486,7 +1187,7 @@ exports.install = function(instance) {
{
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3});
- deviceStatuses["state_of_breaker"][line + 3] = value;
+ deviceStatus["state_of_breaker"][line + 3] = value;
reportLineStatus(line + 3);
values[type] = value;
@@ -1495,95 +1196,50 @@ exports.install = function(instance) {
delete values[type];
}
-
}
}
if(value == "Off") values["status"] = "NOK";
-
- deviceStatuses["state_of_breaker"][line] = value;
+ deviceStatus["state_of_breaker"][line] = value;
reportLineStatus(line);
}
+ else return;
values[type] = value;
-
- //if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode();
- if(pinsData.hasOwnProperty(pinIndex))
+ if(type == "rotary_switch_state")
{
- let valueChanged = false;
- if(newPinValue != previousValues[pinIndex])
- {
- valueChanged = true;
- //pin was changed
- previousValues[pinIndex] = newPinValue;
- }
-
- let result = checkFinalRVOStatus();
- if(!result && line == 0)
- {
- values["status"] = "NOK";
- }
-
- if(type == "state_of_contactor") valueChanged = true;
- if(type == "rotary_switch_state") valueChanged = true;
- if(type === "state_of_breaker")
- {
- //console.log(type, values, valueChanged);
- }
-
- if(FLOW.OMS_rvo_tbname == "")
- {
- console.log("FLOW.OMS_rvo_tbname is EMPTY");
- }
-
- if(FLOW.OMS_rvo_tbname == tbname)
- {
- values["statecode"] = calculateStateCode();
- //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname);
- }
-
- if(valueChanged)
- {
- sendTelemetry(values, tbname);
- }
-
- if(type == "rotary_switch_state")
- {
- if(FLOW.OMS_maintenance_mode) value = "maintenance";
- value = value.toLowerCase();
-
- let values = {};
- values["power_mode"] = value;
-
- sendTelemetry(values, tbname);
- }
- }
- else
- {
- logger.debug("no pinIndex", pinsData[pinIndex], pinsData);
+ if(SETTINGS.maintenance_mode) value = "maintenance";
+ value = value.toLowerCase();
+ values["power_mode"] = value;
}
+ if(newPinValue != previousValues[pinIndex]) previousValues[pinIndex] = newPinValue;
+ if(Object.keys(values).length > 0 && tbname) sendTelemetry(values, tbname);
}
- function sendTelemetry(values, tbname)
- {
+ function sendTelemetry(values, tbname, date=Date.now()) {
let dataToTb = {
[tbname]: [
{
- "ts": Date.now(),
+ "ts": date,
"values": values
}
]
- }
+ };
- instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
}
-}
+
+ function isObject (item) {
+ return (typeof item === "object" && !Array.isArray(item) && item !== null);
+ }
+
+} //end of instance
@@ -1860,25 +1516,52 @@ exports.install = function(instance) {
//! pins_data --> from UNIPI
// {
-// '16': { pin: '16', type: 'twilight_sensor', line: 0 },
-// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 },
-// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 },
-// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 },
-// al_power: { pin: 'al_power', type: 'power_supply', line: 0 },
-// al_battery: { pin: 'al_battery', type: 'battery', line: 0 },
-// al_door: { pin: 'al_door', type: 'door_condition', line: 0 },
-// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 },
-// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 },
-// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 },
-// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 },
-// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 },
-// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 },
-// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 },
-// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 },
-// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', line: 0 }
+// input1_01: {
+// pin: 'input1_01',
+// type: 'door_condition',
+// line: 0,
+// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
+// },
+// input1_02: {
+// pin: 'input1_02',
+// type: 'rotary_switch_state',
+// line: 0,
+// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
+// },
+// input1_03: {
+// pin: 'input1_03',
+// type: 'rotary_switch_state',
+// line: 0,
+// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
+// },
+// input1_04: {
+// pin: 'input1_04',
+// type: 'power_supply',
+// line: 0,
+// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
+// },
+// input1_05: {
+// pin: 'input1_05',
+// type: 'state_of_main_switch',
+// line: 0,
+// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
+// },
+// input1_06: {
+// pin: 'input1_06',
+// type: 'state_of_breaker',
+// line: 1,
+// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
+// },
+// relay1_02: {
+// pin: 'relay1_02',
+// type: 'state_of_contactor',
+// line: 1,
+// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
+// },
+// '28F46E9D0E00008B': { pin: '28F46E9D0E00008B', type: 'temperature', line: 0 },
+// twilight_sensor: { pin: 'twilight_sensor', type: 'twilight_sensor', line: 0 }
// }
-
//! relays_data
// {
// '0': {
diff --git a/flow/empty.js b/flow/empty.js
new file mode 100644
index 0000000..1e19c10
--- /dev/null
+++ b/flow/empty.js
@@ -0,0 +1,43 @@
+exports.id = 'id_bez_pomlcky';
+exports.title = 'nazov';
+exports.version = '1.0.0';
+exports.group = 'Worksys';
+exports.color = '#2134B0';
+exports.input = 1;
+exports.output = ["red", "white"];
+exports.click = false;
+exports.author = 'Daniel Segeš';
+exports.icon = 'bolt';
+exports.options = { edge: "undefined" };
+//exports.npm = ['serialport'];
+
+exports.html = ``;
+
+exports.readme = `# readme`;
+
+
+
+exports.install = function(instance) {
+
+
+
+ instance.on("close", () => {
+
+ })
+
+
+ instance.on("data", (flowdata) => {
+
+
+ })
+
+
+}
+
+
diff --git a/flow/gettemperature.txt b/flow/gettemperature.txt
new file mode 100644
index 0000000..12d9d60
--- /dev/null
+++ b/flow/gettemperature.txt
@@ -0,0 +1,151 @@
+exports.id = 'gettemperature';
+exports.title = 'Thermometer';
+exports.group = 'Worksys';
+exports.color = '#5CB36D';
+exports.version = '1.0.2';
+exports.input = 1;
+exports.output = ["red", "white", "blue"];
+exports.author = 'Rastislav Kovac';
+exports.icon = 'thermometer-three-quarters';
+
+exports.readme = `# Getting temperature values from RVO`;
+
+const { errLogger, logger, monitor } = require('./helper/logger');
+
+const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ di_do_controller: 2
+}
+
+//read temperature - frequency
+let timeoutMin = 5;//minutes
+
+
+exports.install = function(instance) {
+
+ const { exec } = require('child_process');
+ const { sendNotification } = require('./helper/notification_reporter.js');
+
+ let startRead;
+ let dataToTb;
+ let counter = 0;
+
+ let SETTINGS;
+ let temperatureAddress = "";
+ let rvoTbName = "";
+
+
+ logger.debug(exports.title, "installed");
+
+ instance.on("close", function(){
+ clearInterval(startRead);
+ })
+
+
+ const main = function(){
+
+ try {
+
+ if(SETTINGS.controller_type === "unipi")
+ {
+ clearInterval(startRead);
+ return;
+ }
+
+ if(temperatureAddress === "") throw "gettemperature: temperatureAddress is not defined";
+
+ exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
+
+ if(!error)
+ {
+ parseData(stdout)
+ return;
+ }
+
+ sendNotification("main", rvoTbName, "thermometer_is_not_responding", {}, {"Error": error}, SEND_TO.tb, instance, "thermometer");
+ logger.debug("gettemparature", error);
+ monitor.info("Thermometer is not responding", error);
+
+ dataToTb = {
+ [rvoTbName]: [
+ {
+ "ts": Date.now(),
+ "values": {
+ "status": "NOK"
+ }
+ }
+ ]
+ }
+
+ instance.send(SEND_TO.tb, dataToTb);
+ instance.send(SEND_TO.di_do_controller, {sender: "gettemperature", status: "NOK"});
+ });
+
+ }
+ catch(err) {
+ errLogger.error(exports.title, err);
+ clearInterval(startRead);
+ }
+ }
+
+ const parseData = function(data) {
+
+ data = parseFloat(data);
+ logger.debug("gettemperature", data);
+
+ if (!isNaN(data)){
+
+
+ if(counter > 290)
+ {
+ instance.send(SEND_TO.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break");
+ sendNotification("parseData", rvoTbName, "thermometer_is_responding_again", {}, "", SEND_TO.tb, instance, "thermometer");
+ }
+
+ logger.debug("gettemperature", data);
+
+ dataToTb = {
+ [rvoTbName]: [
+ {
+ "ts": Date.now(),
+ "values": {
+ "temperature": Number(data.toFixed(2)),
+ "status": "OK"
+ }
+ }
+ ]
+ }
+
+ instance.send(SEND_TO.tb, dataToTb);
+ instance.send(SEND_TO.di_do_controller, {sender: "gettemperature", status: "OK"});
+
+ counter = 0;
+
+ } else {
+
+ counter++;
+ monitor.info("gettemperature err", counter, data);
+
+ //ked je problem 1 den
+ let day = 24 * 60 / timeoutMin;
+ if(counter > day && counter < day + 2) {
+ sendNotification("parseData", rvoTbName, "thermometer_sends_invalid_data", {}, "", SEND_TO.tb, instance, "thermometer");
+
+ instance.send(SEND_TO.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day");
+ instance.send(SEND_TO.di_do_controller, {sender: "gettemperature", status: "NOK"});
+ }
+
+ }
+
+ }
+
+ instance.on("data", _ => {
+ SETTINGS = FLOW.GLOBALS.settings;
+ temperatureAddress = SETTINGS.temperature_address;
+ rvoTbName = SETTINGS.rvoTbName;
+ startRead = setInterval(main, timeoutMin * 1000 * 60);
+ main();
+ })
+
+};
\ No newline at end of file
diff --git a/flow/helper/DataToTbHandler.js b/flow/helper/DataToTbHandler.js
index 8fff312..a89b75b 100644
--- a/flow/helper/DataToTbHandler.js
+++ b/flow/helper/DataToTbHandler.js
@@ -1,8 +1,11 @@
-class DataToTbHandler
-{
+class DataToTbHandler {
+
constructor(index) {
this.index = index;
+ // time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
+ this.timeToHoldTbValue = 30*60; //30 minutes
+
this.previousValues = {};
this.debug = false;
this.messageCounter = 0;
@@ -10,42 +13,33 @@ class DataToTbHandler
this.sender = "";
}
- dump()
- {
+ dump() {
console.log("----------------------------");
console.log("previousValues", this.previousValues);
console.log("----------------------------");
}
- setSender(sender)
- {
+ setSender(sender) {
this.sender = sender;
}
- isEmptyObject( obj ) {
- for ( var name in obj ) {
- return false;
+ isEmptyObject(obj) {
+ for (var name in obj) {
+ return false;
}
return true;
}
- sendToTb(dataToTb, instance)
- {
-
- if(!FLOW.OMS_brokerready)
- {
- return dataToTb;
- }
+ sendToTb(dataToTb, instance) {
let keys = Object.keys(dataToTb);
if(keys.length == 0)
{
- if(this.debug) console.log("sendToTb received epty object", dataToTb);
+ if(this.debug) console.log("sendToTb received empty object", dataToTb);
return;
}
-
let tbname = keys[0];
let ts;
@@ -55,16 +49,11 @@ class DataToTbHandler
for(let i = 0; i < arrayOfValues.length; i++)
{
ts = arrayOfValues[i].ts;
-
- //console.log("sendToTb------------>before", arrayOfValues[i].values, tbname);
-
let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
- //console.log("sendToTb------------>after", values);
-
if(!this.isEmptyObject(values))
{
- arrayOfValuesToSend.push({ts: ts, values: values});
+ arrayOfValuesToSend.push({ts: ts, values: values});
}
}
@@ -74,17 +63,6 @@ class DataToTbHandler
return;
}
- /*
- let dataToTb = {
- [tbname]: [
- {
- "ts": Date.now(),
- "values": values
- }
- ]
- }
- */
-
this.messageCounter++;
let dataToTbModified = {
@@ -92,26 +70,18 @@ class DataToTbHandler
}
//console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
- if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
-
+ //if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
instance.send(this.index, dataToTbModified);
}
- getDiffTimestamp(key)
- {
- let seconds = 60*60;//1h
- //seconds = 1;//for testing
-
+ getDiffTimestamp(key) {
//TODO set different value for given key!!!
- //if(key == "status") seconds = 2*60*60;//2h
-
- let timestampDiffToRemoveKey = seconds*1000;
-
- return timestampDiffToRemoveKey;
+ //if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
+ return this.timeToHoldTbValue * 1000;
}
- prepareValuesForTb(tbname, timestamp, values)
- {
+ prepareValuesForTb(tbname, timestamp, values) {
+
let keys = Object.keys(values);
if(!this.previousValues.hasOwnProperty(tbname))
{
@@ -160,4 +130,4 @@ class DataToTbHandler
}
}
-module.exports = DataToTbHandler;
\ No newline at end of file
+module.exports = DataToTbHandler;
diff --git a/flow/helper/ErrorToServiceHandler.js b/flow/helper/ErrorToServiceHandler.js
index dc60446..110ea8b 100644
--- a/flow/helper/ErrorToServiceHandler.js
+++ b/flow/helper/ErrorToServiceHandler.js
@@ -97,7 +97,9 @@ class ErrorToServiceHandler
console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender);
//TODO UGLY!!!
- if(this.projects_id === undefined) this.projects_id = FLOW.OMS_projects_id;
+ // if error occures too early FLOW.GLOBALs.settings.project_id is still undefined
+ // if(this.projects_id === undefined) this.projects_id = FLOW.GLOBALS.settings.project_id;
+ if(this.projects_id === undefined) return;
/*
if(this.projects_id === undefined)
diff --git a/flow/helper/error_reporter.js b/flow/helper/error_reporter.js
deleted file mode 100644
index 2b84369..0000000
--- a/flow/helper/error_reporter.js
+++ /dev/null
@@ -1,72 +0,0 @@
-
-//key is device, value = str
-let sentValues= {};
-
-function sendError(func, device, weight, str, extra, tb_output, instance, type) {
- // if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
- // return; // Allow debug messages only if CONFIG.debug is active
- // }
-
- let key = device;
- if(type != undefined) key = type;
-
- if(sentValues.hasOwnProperty(key))
- {
- if(sentValues[key] == str)
- {
- return;
- }
- }
-
- sentValues[key] = str;
-
- let content = {
- "type": weight,
- "status": "new",
- "source": {
- "func":func,
- "component":instance.id,
- "component_name":instance.name,
- "edge":device
- },
- "message":str,
- "message_data": extra
- };
-
- let msg = {};
- msg[device] = [
- {
- "ts": Date.now(),
- "values": {
- "_event":content
- }
- }
- ];
-
- // Msg can be outputted from components only after configuration
- /*if (canSendErrData()){
- sendBufferedErrors();
- } else {
- bufferError(msg);
- }*/
- instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
-
-}
-
-
-let ERRWEIGHT = {
- EMERGENCY: "emergency", // System unusable
- ALERT: "alert", // Action must be taken immidiately
- CRITICAL: "critical", // Component unable to function
- ERROR: "error", // Error, but component able to recover from it
- WARNING: "warning", // Possibility of error, system running futher
- NOTICE: "notice", // Significant message but not an error, things user might want to know about
- INFO: "informational", // Info
- DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
-};
-
-
-module.exports = {
- sendError,
- ERRWEIGHT
-}
\ No newline at end of file
diff --git a/flow/helper/error_reporting.js b/flow/helper/error_reporting.js
deleted file mode 100644
index 62dace5..0000000
--- a/flow/helper/error_reporting.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const ERRWEIGHT = {
- EMERGENCY: "emergency", // System unusable
- ALERT: "alert", // Action must be taken immidiately
- CRITICAL: "critical", // Component unable to function
- ERROR: "error", // Error, but component able to recover from it
- WARNING: "warning", // Possibility of error, system running futher
- NOTICE: "notice", // Significant message but not an error, things user might want to know about
- INFO: "informational", // Info
- DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
-};
-
-
-
-
-function sendError(func, device, weight, str, extra){
- if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
- return; // Allow debug messages only if CONFIG.debug is active
- }
-
- let content = {
- "type": weight,
- "status": "new",
- "source": {
- "func":func,
- "component":instance.id,
- "component_name":instance.name,
- "edge":myEdge
- },
- "message":str,
- "message_data": extra
- };
- let msg = {};
- msg[device] = [
- {
- "ts": Date.now(),
- "values": {
- "_event":content
- }
- }
- ];
-
- // Msg can be outputted from components only after configuration
- /*if (canSendErrData()){
- sendBufferedErrors();
- } else {
- bufferError(msg);
- }*/
- instance.send(0, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
-
-}
-
-
-module.exports = {
- sendError,
- ERRWEIGHT,
-}
\ No newline at end of file
diff --git a/flow/helper/logger.js b/flow/helper/logger.js
new file mode 100644
index 0000000..2585639
--- /dev/null
+++ b/flow/helper/logger.js
@@ -0,0 +1,30 @@
+//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
+//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
+
+var log4js = require("log4js");
+var path = require('path');
+
+log4js.configure({
+appenders: {
+ errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'err.txt') },
+ monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'monitor.txt') },
+ console: { type: 'console' }
+},
+categories: {
+ errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
+ monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
+ //another: { appenders: ['console'], level: 'trace' },
+ default: { appenders: ['console'], level: 'trace' }
+}
+});
+
+const errLogger = log4js.getLogger("errLogs");
+const logger = log4js.getLogger();
+const monitor = log4js.getLogger("monitorLogs");
+
+//USAGE
+//logger.debug("text")
+//monitor.info('info');
+//errLogger.error("some error");
+
+module.exports = { errLogger, logger, monitor };
\ No newline at end of file
diff --git a/flow/helper/notification_reporter.js b/flow/helper/notification_reporter.js
index 84b2345..61c0aef 100644
--- a/flow/helper/notification_reporter.js
+++ b/flow/helper/notification_reporter.js
@@ -1,10 +1,6 @@
-
-const { promisifyBuilder, makeMapFromDbResult } = require('./db_helper.js');
-const dbNotifications = TABLE("notifications");
-
//key is device, value = str
let sentValues= {};
-let notificationsData = {};
+let notificationsData = null;
let ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
@@ -24,12 +20,9 @@ function getKey(map, val) {
//https://stackoverflow.com/questions/41117799/string-interpolation-on-variable
var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);
-async function initNotifications()
-{
- let response = await promisifyBuilder(dbNotifications.find());
- notificationsData = makeMapFromDbResult(response, "key");
- console.log("initNotifications done" );
+function initNotification() {
+ notificationsData = FLOW.GLOBALS.notificationsData;
}
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
@@ -39,7 +32,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
let storeToSendValues = true;
if(saveKey == undefined) storeToSendValues = false;
- let lang = FLOW.OMS_language;
+ let lang = FLOW.GLOBALS.settings.language;
if(lang != "en" || lang != "sk") lang = "en";
let tpl = key;
@@ -55,7 +48,8 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
}
else
{
- console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
+ //console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
+ console.error("sendNotification: Notifications: undefined key", key, func );
return false;
}
@@ -91,7 +85,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
if(storeToSendValues) sentValues[saveKey] = tpl;
- let str = FLOW.OMS_rvo_name;
+ let str = FLOW.GLOBALS.settings.rvo_name;
if(str != "") str = str + ": ";
str = str + tpl;
@@ -132,6 +126,6 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
module.exports = {
sendNotification,
- initNotifications,
- ERRWEIGHT
-}
\ No newline at end of file
+ ERRWEIGHT,
+ initNotification
+}
diff --git a/flow/helper/serialport_helper.js b/flow/helper/serialport_helper.js
index a84ab84..4a0edd5 100644
--- a/flow/helper/serialport_helper.js
+++ b/flow/helper/serialport_helper.js
@@ -1,94 +1,100 @@
const { exec } = require('child_process');
function openPort(port){
- return new Promise((resolve, reject) => {
+ return new Promise((resolve, reject) => {
- var callbackError = function(err) {
- port.removeListener('error', callbackError);
- port.removeListener('open', callbackError);
+ var callbackError = function(err) {
+ port.removeListener('error', callbackError);
+ port.removeListener('open', callbackError);
- reject(err.message);
- };
+ reject(err.message);
+ };
- var callbackOpen = function(data) {
- port.removeListener('error', callbackError);
- port.removeListener('open', callbackOpen);
+ var callbackOpen = function(data) {
+ port.removeListener('error', callbackError);
+ port.removeListener('open', callbackOpen);
- resolve("port open: ok");
- };
+ resolve("port open: ok");
+ };
- port.on('error', callbackError);
- port.on('open', callbackOpen);
+ port.on('error', callbackError);
+ port.on('open', callbackOpen);
- port.open();
+ port.open();
- })
- }
+ })
+}
- function runSyncExec(command){
- return new Promise((resolve, reject) => {
-
- exec(command, (error, stdout, stderr) => {
- if(error == null) resolve(stdout);
- reject(error);
- });
-
- })
- }
+function runSyncExec(command){
+ return new Promise((resolve, reject) => {
- async function writeData(port, data, readbytes, timeout){
- return new Promise((resolve, reject) => {
+ exec(command, (error, stdout, stderr) => {
+ if(error == null) resolve(stdout);
+ reject(error);
+ });
- //readbytes = 0 = broadcast
- if(readbytes == undefined) readbytes = 0;
- if(timeout == undefined) timeout = 10000;//10s, default timeout MASTERA je 3s
+ })
+}
- //cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
-
- var callback = function(data) {
- rsPortReceivedData.push(...data);
- let l = rsPortReceivedData.length;
+async function writeData(port, data, readbytes, timeout){
+ return new Promise((resolve, reject) => {
- if(l >= readbytes)
- {
- port.removeListener('data', callback);
-
- clearTimeout(t);
- resolve(rsPortReceivedData);
- }
- };
-
- port.removeListener('data', callback);
-
- let t = setTimeout(() => {
- port.removeListener('data', callback);
-
- console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
-
- reject("TIMEOUT READING");
- }, timeout);
-
- let rsPortReceivedData = [];
-
- if(readbytes > 0) port.on('data', callback);
+ // If first item in data array is 255, we just write broadcast command to rsPort
+ // We wait 3 seconds and resolve(["broadcast"])
+ // It is important to resolve with array
+ if(data[0] == 255) {
port.write(Buffer.from(data), function(err) {
if (err) {
- port.removeListener('data', callback);
reject(err.message);
}
-
- if(readbytes == 0)
- {
- resolve(rsPortReceivedData);
- }
-
});
- })
+
+ setTimeout(resolve, 3000, ["broadcast"]);
+ return;
+ }
+
+ //cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
+
+ var callback = function(data) {
+ rsPortReceivedData.push(...data);
+ let l = rsPortReceivedData.length;
+
+ if(l >= readbytes)
+ {
+ port.removeListener('data', callback);
+
+ clearTimeout(t);
+ resolve(rsPortReceivedData);
+ }
+ };
+
+ port.removeListener('data', callback);
+
+ let t = setTimeout(() => {
+ port.removeListener('data', callback);
+
+ console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
+
+ reject("TIMEOUT READING");
+ }, timeout);
+
+ let rsPortReceivedData = [];
+
+ port.on('data', callback);
+
+ port.write(Buffer.from(data), function(err) {
+ if (err) {
+ port.removeListener('data', callback);
+ reject(err.message);
+ }
+
+ });
+ })
}
module.exports = {
openPort,
runSyncExec,
writeData
-}
\ No newline at end of file
+}
diff --git a/flow/infosender.js b/flow/infosender.js
index a83499c..c7afd83 100644
--- a/flow/infosender.js
+++ b/flow/infosender.js
@@ -3,12 +3,9 @@ exports.title = 'Info sender';
exports.version = '1.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
-exports.input = 1;
+exports.input = 2;
exports.output = 1
-exports.click = false;
-exports.author = 'oms-is';
exports.icon = 'bolt';
-exports.options = { edge: "undefined" };
const { networkInterfaces } = require('os');
@@ -22,13 +19,12 @@ exports.html = `
exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`;
-const fs = require('fs');
-var path = require('path');
+exports.install = function(instance) {
-exports.install = async function(instance) {
-
+ let id;
let allValues = {};
let sendAllValuesInterval;
+ let configured = false;
let now = new Date();
console.log(exports.title, "INSTALLED", now.toLocaleString("sk-SK"));
@@ -47,23 +43,19 @@ exports.install = async function(instance) {
}
}
}
-
function sendValues()
{
- const id = FLOW.OMS_projects_id;
+ if(!configured) return;
if(Object.keys(allValues).length > 0)
{
- if(id !== undefined)
+ if(id)
{
delete allValues.__force__;
let dataToSend = {...allValues};
dataToSend.id = id;
dataToSend.ipAddresses = ipAddresses;
- //dataToSend.notify_date = new Date().toISOString().slice(0, 19).replace('T', ' ');
-
- //console.log(exports.title, "------------>sendValues", dataToSend);
instance.send(0, dataToSend);
@@ -71,7 +63,7 @@ exports.install = async function(instance) {
}
else
{
- console.log(exports.title, "unable to send data, id is undefined");
+ console.log(exports.title, "unable to send data, no id");
}
}
@@ -81,10 +73,14 @@ exports.install = async function(instance) {
clearInterval(sendAllValuesInterval);
})
- instance.on("data", (flowdata) => {
+ instance.on("0", _ => {
+ id = FLOW.GLOBALS.settings.project_id;
+ configured = true;
+ })
+
+ instance.on("1", flowdata => {
allValues = { ...allValues, ...flowdata.data};
-
//console.log("DATA RECEIVED", flowdata.data);
//__force__
diff --git a/flow/modbus_citysys.js b/flow/modbus_citysys.js
new file mode 100644
index 0000000..d038b69
--- /dev/null
+++ b/flow/modbus_citysys.js
@@ -0,0 +1,1127 @@
+exports.id = 'modbus_citysys';
+exports.title = 'Modbus_citysys';
+exports.version = '1.0.0';
+exports.group = 'Worksys';
+exports.color = '#2134B0';
+exports.input = 1;
+exports.output = ["red", "white", "blue", "orange"];
+exports.click = false;
+exports.author = 'Jakub Klena';
+exports.icon = 'bolt';
+exports.options = { edge: "undefined" };
+
+exports.html = `
`;
+
+exports.readme = `# Energomonitor
+## Outputs
+
+ - *Red* - ERROR output (can connect to filewriter or something)
+ - *White* - STATUS output (answers to your commands, ERRORS and WARNINGS from your commands go both to this and to their own outputs, so they get logged)
+ - *Blue* - TB output (pure data for TB)
+`;
+
+
+const instanceSendTo = {
+ error: 0,
+ debug: 1,
+ tb: 2,
+ di_do_controller: 3
+}
+
+const DataToTbHandler = require('./helper/DataToTbHandler.js');
+const { sendNotification } = require('./helper/notification_reporter.js');
+const dbRelays = TABLE("relays");
+const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
+let tbname;
+
+async function loadSettings()
+{
+ //todo global FLOW.OMS_edgeName is making problem, so we load it here as well, it should not be
+ let responseRelays = await promisifyBuilder(dbRelays.find());
+ FLOW.OMS_edgeName = responseRelays[0]["tbname"];
+ tbname = FLOW.OMS_edgeName;
+}
+
+loadSettings();
+
+exports.install = function(instance) {
+ const SerialPort = require('serialport');
+ const { exec } = require('child_process');
+ const fs = require("fs");
+ const filepath = F.path.root("saved_data/modbus_settings");
+ const backup_filepath = F.path.root("saved_data/modbus_settings_backup");
+
+ const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
+ const errorHandler = new ErrorToServiceHandler();
+
+ let receivedDataArray = [];
+
+
+ instance.CONFIG = {
+ "isRunning": false,
+ "debug": true,
+ "timeoutTime": 10000,
+ "msgWaitTime": 1000,
+ "port": "/dev/ttymxc1",
+ //"port_options": "stty -F /dev/ttymxc1 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke"
+ "port_options": "stty -F /dev/ttymxc1 9600 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke"
+ };
+
+ let PRIVATEVARS = {
+ "errBuffer": [], // Buffer for error messages
+ "tbBuffer": [], // Buffer for TB push messages
+ "device_index": 0,
+ "cmd_index": -1,
+ "devices": [
+ /*{
+ "name": "Elektrometer 1",
+ "tb_name": "EOzNMgZ9n43qPbjXmy7zwdA2DKdYvW5e6pxGRrVa",
+ "type": "EM111",
+ "address": 1,
+ "data":[],
+ "cmd":[],
+ "timeoutcount":0,
+ "status":"virtual"
+ },*/
+ // {
+ // "name": "Elektrometer 2",
+ // "tb_name": "pJX1ObgmqGZ54DMyYL7aDdkEVdve38WKRzwjNrQ9",
+ // "type": "EM111",
+ // "address": 2,
+ // "data":[],
+ // "cmd":[],
+ // "timeoutcount":0,
+ // "status":"virtual"
+ // },
+ // {
+ // "name": "Elektrometer 3",
+ // "tb_name": "XRvmwNz8QPblKp41GD7lKVkJrLVYoBO92dMegn6W",
+ // "type": "EM111",
+ // "address": 3,
+ // "data":[],
+ // "cmd":[],
+ // "timeoutcount":0,
+ // "status":"virtual"
+ // },
+ // {
+ // "name": "Elektrometer 4",
+ // "tb_name": "oRO8rjaBDy21qPQJzW7oD9ApK3xmNleVZg9Ed4Gw",
+ // "type": "EM111",
+ // "address": 4,
+ // "data":[],
+ // "cmd":[],
+ // "timeoutcount":0,
+ // "status":"virtual"
+ // },
+ {
+ "name": "Elektrometer 1",
+ "tb_name": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV",
+ "type": "EM340",
+ "address": 1,
+ "data":[],
+ "cmd":[],
+ "timeoutcount":0,
+ "status":"virtual"
+ }
+ ],
+ "cmd_tables": [
+ {
+ "type":"EM340",
+ "cmd":[
+ {
+ "name": "Voltage L1",
+ "tb_name": "a",
+ "register": 0,
+ "size": 2,
+ "multiplier": 0.1
+ },
+ {
+ "name": "Voltage L2",
+ "tb_name": "b",
+ "register": 2,
+ "size": 2,
+ "multiplier": 0.1
+ },
+ {
+ "name": "Voltage L3",
+ "tb_name": "c",
+ "register": 4,
+ "size": 2,
+ "multiplier": 0.1
+ },
+ {
+ "name": "Current L1",
+ "tb_name": "d",
+ "register": 12,
+ "size": 2,
+ "multiplier": 0.001
+ },
+ {
+ "name": "Current L2",
+ "tb_name": "e",
+ "register": 14,
+ "size": 2,
+ "multiplier": 0.001
+ },
+ {
+ "name": "Current L3",
+ "tb_name": "f",
+ "register": 16,
+ "size": 2,
+ "multiplier": 0.001
+ }
+
+
+ // {
+ // "name": "Power factor",
+ // "tb_name": "power_factor",
+ // "register": 14,
+ // "size": 1,
+ // "multiplier": 0.001
+ // },
+ // {
+ // "name": "Frequency",
+ // "tb_name": "frequency",
+ // "register": 15,
+ // "size": 1,
+ // "multiplier": 0.1
+ // },
+ // {
+ // "name": "Energy",
+ // "tb_name": "consumption",
+ // "register": 16,
+ // "size": 2,
+ // "multiplier": 0.1
+ // }
+ ]
+ }
+ ]
+ };
+
+ let ERRWEIGHT = {
+ EMERGENCY: "emergency", // System unusable
+ ALERT: "alert", // Action must be taken immidiately
+ CRITICAL: "critical", // Component unable to function
+ ERROR: "error", // Error, but component able to recover from it
+ WARNING: "warning", // Possibility of error, system running futher
+ NOTICE: "notice", // Significant message but not an error, things user might want to know about
+ INFO: "informational", // Info
+ DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
+ };
+
+ instance.currentData = function(){
+ let resp = [];
+ for (let f = 0; f < PRIVATEVARS.devices.length; f++){
+ let dev = PRIVATEVARS.devices[f];
+ for (let e = 0; e < dev.data.length; e++){
+ let d = dev.data[e];
+ resp.push({
+ "name": dev.name+" - "+d.name,
+ "value": d.value
+ });
+ }
+ }
+ return resp;
+ };
+
+ instance.configList = function(){
+ let resp = [];
+ /*let data = PRIVATEVARS.feeds;
+ for (let a = 0; a < data.length; a++){
+ for (let i = 0; i < instance.CONFIG.feeds.length; i++){
+ let feed = instance.CONFIG.feeds[i];
+ if (feed.name === data[a].id){
+ for (let b = 0; b < data[a].streams.length; b++){
+ for (let j = 0; j < feed.streams.length; j++){
+ let stream = feed.streams[j];
+ if (stream.name === data[a].streams[b].id){
+ data[a].streams[b]["exists"] = true;
+ data[a].streams[b]["currently"] = stream;
+ }
+ }
+ }
+ }
+ }
+ }
+ resp.push({
+ "name":"Device manager",
+ "icon":"tasks",
+ "_show":false,
+ "js_func":"energoDevManager",
+ "data": data
+ });*/
+
+ return resp;
+ }
+
+ let timeoutInterval = null;
+ let msgWaitInterval = null;
+ let port = null;
+ let myEdge = "undefined";
+ let starter = null;
+ instance.status("Loading...", "red");
+
+
+ instance.availableCommands = [
+ {
+ "name": "Status",
+ "cmd": "qStatus",
+ "icon": "stream",
+ "func": function(body){
+ let a = true;
+ if (timeoutInterval === null){
+ a = false;
+ }
+ let b = true;
+ if (msgWaitInterval === null){
+ b = false;
+ }
+ let st = {
+ "isRunning":instance.CONFIG.isRunning,
+ "timeoutInterval":a,
+ "msgWaitInterval":b,
+ "CONFIG":instance.CONFIG
+ };
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": st
+ };
+ }
+ },
+ {
+ "name": "Start Reading",
+ "cmd": "sStart",
+ "icon": "play",
+ "func": function(body){
+ /*if (running === false){
+ startCmdWaitInterval();
+ running = true;
+ return "Reading started !";
+ } else {
+ return "Reading already active !";
+ }*/
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": "WIP"
+ };
+ }
+ },
+ {
+ "name": "Stop Reading",
+ "cmd": "sStop",
+ "icon": "stop",
+ "func": function(body){
+ /*if (running === true){
+ stopCmdWaitInterval();
+ stopTimeoutInterval();
+ running = false;
+ return "Reading stopped !";
+ } else {
+ return "Reading already inactive !";
+ }*/
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": "WIP"
+ };
+ }
+ },
+ {
+ "name": "Read current data",
+ "cmd": "qCurrentData",
+ "icon": "chart-bar",
+ "func": function(body){
+ let resp = instance.currentData();
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": resp
+ };
+ }
+ },
+ {
+ "name": "Save current config",
+ "cmd": "saveConfig",
+ "icon": "save",
+ "func": function(body){
+
+ instance.set("config", JSON.stringify(instance.CONFIG));
+ instance.set("private", JSON.stringify(PRIVATEVARS));
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": "done"
+ };
+ }
+ },
+ {
+ "name": "Toggle debug",
+ "cmd": "sDebug",
+ "icon": "comment-dots",
+ "func": function(body){
+
+ if (instance.CONFIG.debug){
+ instance.CONFIG.debug = false;
+ instance.set("config", JSON.stringify(instance.CONFIG));
+
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": "debug OFF"
+ };
+ } else {
+ instance.CONFIG.debug = true;
+ instance.set("config", JSON.stringify(instance.CONFIG));
+
+ return {
+ "type": "ok",
+ "timestamp": humanReadableTimeAndDate(),
+ "resp": "debug ON"
+ };
+ }
+
+ }
+ }
+ ];
+
+
+
+ function saveData(){
+ if (checkFile(filepath)){
+ let content = undefined;
+ try {
+ content = fs.readFileSync(filepath);
+ } catch (err){
+ console.log("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+
+ //sendError("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+ }
+
+ if (content !== undefined){
+ try {
+ fs.writeFileSync(backup_filepath, content, "utf8");
+ } catch (err) {
+ //sendError("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to save backup of configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message});
+ console.log("saveData", myEdge, ERRWEIGHT.ERROR, "Unable to save backup of configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message});
+ }
+ }
+ }
+
+ let a = {
+ "config":instance.CONFIG,
+ "private":PRIVATEVARS
+ };
+
+ try {
+ fs.writeFileSync(filepath, JSON.stringify(a), "utf8");
+ } catch (err) {
+ //sendError("saveData", myEdge, ERRWEIGHT.CRITICAL, "Unable to save configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+ console.log("saveData", myEdge, ERRWEIGHT.CRITICAL, "Unable to save configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+ }
+ }
+
+ function loadData(){
+ let content = undefined;
+ //console.log(filepath);
+ if (checkFile(filepath)){
+ try {
+ content = fs.readFileSync(filepath);
+ } catch (err){
+ //sendError("loadData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+ console.log("loadData", myEdge, ERRWEIGHT.ERROR, "Unable to read original configuration !", {"name":instance.name, "id":instance.id, "file":filepath, "err":err.message});
+ }
+ } else {
+ if (checkFile(backup_filepath)){
+ try {
+ content = fs.readFileSync(backup_filepath);
+ } catch (err){
+ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Unable to read backup configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message});
+ console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Unable to read backup configuration !", {"name":instance.name, "id":instance.id, "file":backup_filepath, "err":err.message});
+ }
+ if (content !== undefined){
+ //sendError("loadData", myEdge, ERRWEIGHT.WARNING, "No configuration, loading from backup !", {"name":instance.name, "id":instance.id});
+ console.log("loadData", myEdge, ERRWEIGHT.WARNING, "No configuration, loading from backup !", {"name":instance.name, "id":instance.id});
+ }
+ } else {
+ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "No configuration, not even backup !", {"name":instance.name, "id":instance.id});
+ console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "No configuration, not even backup !", {"name":instance.name, "id":instance.id, "filepath": filepath});
+ }
+ }
+
+
+
+ if (content !== undefined){
+ let a = JSON.parse(content);
+ instance.send(instanceSendTo.debug, a);
+ let c = a.config;
+ let p = a.private;
+
+
+ if (c === undefined){
+ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Configuration not found !", {"name":instance.name, "id":instance.id});
+ console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Configuration not found !", {"name":instance.name, "id":instance.id});
+ instance.status("Error - no config", "red");
+ } else if (p === undefined){
+ //sendError("loadData", myEdge, ERRWEIGHT.CRITICAL, "Privatevars not found !", {"name":instance.name, "id":instance.id});
+ console.log("loadData", myEdge, ERRWEIGHT.CRITICAL, "Privatevars not found !", {"name":instance.name, "id":instance.id});
+ instance.status("Error - no private vars", "red");
+ } else {
+ instance.CONFIG = c;
+ PRIVATEVARS = p;
+
+ // Daj kazdemu device jeho tabulku prikazu
+ for (let i = 0; i < PRIVATEVARS.devices.length; i++){
+ let device = PRIVATEVARS.devices[i];
+ for (let j = 0; j < PRIVATEVARS.cmd_tables.length; j++){
+ let table = PRIVATEVARS.cmd_tables[j];
+
+ if (device.type === table.type){
+ PRIVATEVARS.devices[i].cmd = table.cmd;
+ }
+ }
+ }
+
+ if (myEdge === "undefined"){
+ instance.status("Unconfigured", "red");
+ } else {
+ instance.status("Running", "green");
+ startCmdWaitInterval();
+
+ instance.CONFIG.isRunning = true;
+ console.log("modbus loaded: ", PRIVATEVARS.devices);
+ }
+ }
+ }
+ }
+
+ function checkFile(name){
+ try {
+ fs.accessSync(name, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK);
+ return true;
+ } catch (err) {
+ return false;
+ }
+ }
+
+ //Zapina slucku vycitavania dat
+ function readDeviceData(){
+ stopCmdWaitInterval();
+
+ // let tbname = FLOW.OMS_edgeName;
+
+ // Check port existance
+ if (port === null)
+ {
+ port = new SerialPort(instance.CONFIG.port);
+
+ port.on('error', function(err) {
+ //logger.debug("rsPort opened error - failed", err.message);
+ //instance.send(instanceSendTo.debug, err.message);
+
+ errorHandler.sendMessageToService( exports.title + " MODBUS RS485 open - failed: " + err.message);
+ })
+
+ port.on('open', function() {
+
+ console.log("--->MODBUS RS485 READY - port opened");
+
+ exec("sudo halfduplex /dev/ttymxc1", (error, stdout, stderr) => {
+ instance.send(instanceSendTo.debug, {"err": error});
+
+ if (error) {
+ console.log("--->MODBUS RS485", error, stderr);
+ errorHandler.sendMessageToService( exports.title + " sudo halfduplex /dev/ttymxc1 - failed: " + error);
+ }
+
+ });
+
+ exec(instance.CONFIG.port_options, (error, stdout, stderr) => {
+ instance.send(instanceSendTo.debug, {"stdout":stdout,"stderr":stderr,"err":error});
+
+ if (error) {
+ console.log("--->MODBUS RS485", error, stderr);
+ errorHandler.sendMessageToService( exports.title + " " + instance.CONFIG.port_options + " - failed: " + error);
+ }
+
+ });
+
+ });
+
+ port.on('data', receivedData);
+
+ //sendError("readDeviceData", myEdge, ERRWEIGHT.DEBUG, "Serial port open!", {});
+ //console.log("-->MODBUS readDeviceData", myEdge, ERRWEIGHT.DEBUG, "Serial port open!", {});
+
+ startCmdWaitInterval();
+ return; // Cakame na port aby sa spravne otvoril a rozbehol
+ }
+
+
+ // Skontroluj existenciu device listu
+ if (PRIVATEVARS.devices.length > 0){
+ // Ponastavuj indexy
+ PRIVATEVARS.cmd_index++;
+ if (PRIVATEVARS.cmd_index >= PRIVATEVARS.devices[PRIVATEVARS.device_index].cmd.length){
+ // Kedže všetky príkazy pre daný device sú vybavené, je treba odoslat vyčítané data do TB
+ updateDataInTB();
+
+ PRIVATEVARS.cmd_index = 0;
+ PRIVATEVARS.device_index++;
+
+ if (PRIVATEVARS.device_index >= PRIVATEVARS.devices.length){
+ PRIVATEVARS.device_index = 0;
+ }
+ }
+
+ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index];
+
+ // Skontroluj existenciu príkazú pre daný device type
+ if (device.cmd.length < 1){
+ //sendError("readDeviceData", tbname, ERRWEIGHT.ERROR, "No commands for this device type !", {"type": device.type});
+ console.log("readDeviceData", tbname, ERRWEIGHT.ERROR, "No commands for this device type !", {"type": device.type});
+ startCmdWaitInterval();
+ return;
+ }
+
+ // Odešli nasledujúci príkaz
+ sendCommand();
+
+ } else {
+ instance.CONFIG.isRunning = false;
+ //sendError("readDeviceData", myEdge, ERRWEIGHT.CRITICAL, "Modbus has no devices registered!", {});
+ console.log("modbus_citys: readDeviceData", myEdge, ERRWEIGHT.CRITICAL, "Modbus has no devices registered!", {});
+ }
+ }
+
+ function readingTimeouted(){
+ stopCmdWaitInterval();
+ stopTimeoutInterval();
+
+ // let tbname = FLOW.OMS_edgeName;
+
+ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index];
+ let com = device.cmd[PRIVATEVARS.cmd_index];
+ //sendError("readingTimeouted", tbame, ERRWEIGHT.WARNING, "Reading timeouted !", {"device": device.address, "cmd": com.register});
+ console.log("modbus_citys: readingTimeouted", tbname, ERRWEIGHT.WARNING, "Reading timeouted !", {"device": device.address, "cmd": com.register});
+
+ device.timeoutcount++;
+ //console.log("device.timeoutcount", device.timeoutcount);
+ if (device.timeoutcount === 16)
+ {
+
+ //sendError("modbus_citys: readingTimeouted", tbname, ERRWEIGHT.CRITICAL, "Electrometer is not responding - reading timeouted", "");
+ sendNotification("modbus_citys: readingTimeouted", tbname, "electrometer_is_not_responding", {}, "", instanceSendTo.tb, instance );
+
+ if (device.status === "OK"){
+ device.status === "NOK";
+ }
+ }
+
+ startCmdWaitInterval();
+ }
+
+ function receivedData(data){
+
+ //let array = [...data];
+ //console.log("received data", array);
+
+ // let tbname = FLOW.OMS_edgeName;
+
+ //!if received data are less than 9 bytes, we store it in array variable and return. than we concatenate second incoming
+ // data and then length of array is 9
+ receivedDataArray = [...receivedDataArray, ...data];
+ //if (array.length < 9) return;
+ let l = receivedDataArray.length;
+ //console.log("received",receivedDataArray, l)
+
+ if ( l < 7 || l > 9 || l == 8 ) return;
+
+ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index];
+ let com = device.cmd[PRIVATEVARS.cmd_index];
+
+ if (device.timeoutcount > 16) {
+ //sendError("Modbus_citysys: receivedData", tbname, ERRWEIGHT.NOTICE, "Electrometer is responding again", "");
+ sendNotification("modbus_citys: receivedData", tbname, "electrometer_is_responding_again", {}, "", instanceSendTo.tb, instance );
+ }
+
+ device.timeoutcount = 0;
+
+ if ((l == 7 && com.size != 1) || ( l == 9 && com.size != 2)) return;
+
+ stopTimeoutInterval();
+
+ //sendError("receivedData", tbname, ERRWEIGHT.DEBUG, "Received data !", {"cmd": receivedDataArray});
+ //console.log("receivedData", tbname, ERRWEIGHT.DEBUG, "Received data !", {"cmd": receivedDataArray});
+
+ // Skontroluj či sedí počet bytú v správe
+ //console.log("com size", com.size*2, "array2", receivedDataArray[2]);
+ if (receivedDataArray[2] !== (com.size*2)){
+ //sendError("receivedData", tbname, ERRWEIGHT.ERROR, "Received data of incorrect size !", {"expected": (com.size*2), "received": receivedDataArray[2], "cmd": com.register, "whole_msg": receivedDataArray});
+ console.log("modbus_citys: receivedData", tbname, ERRWEIGHT.ERROR, "Received data of incorrect size !", {"expected": (com.size*2), "received": receivedDataArray[2], "cmd": com.register, "whole_msg": receivedDataArray});
+ startTimeoutInterval();
+ } else {
+ // Konvertuj raw data na human readable
+
+ let v = (receivedDataArray[3] << 8) | receivedDataArray[4];
+ if (com.size == 2){
+ v = v | (receivedDataArray[5] << 24) | (receivedDataArray[6] << 16);
+ }
+ v = Math.round((v * com.multiplier) * 100) / 100;
+
+
+ // Pokad device nemá ešte žádné hodnoty vyčítané, pushni túto hodnotu do pola
+ if (device.data.length < 1){
+ device.data.push({ // Vždy ked správne zakomunikuje obnov status na OK
+ "changed": true,
+ "name": "status",
+ "value": "OK"
+ });
+ device.data.push({
+ "changed": true,
+ "name": com.tb_name,
+ "value": v
+ });
+ } else {
+ // Kedže už neco v poli má, kukni sa či je tam aj táto hodnota
+ let found = false;
+ for (let i = 0; i < device.data.length; i++){
+ let d = device.data[i];
+ if (d.name == "status"){ // Ked natrefíš na status (vždy tam musí byt) prepíš ho na OK lebo zakomunikoval správne
+ device.data[i].changed = true;
+ device.data[i].value = "OK";
+ }
+
+ if (d.name == com.tb_name){
+ found = true;
+ device.data[i].changed = true;
+ device.data[i].value = v;
+ }
+ }
+
+ // Pole existuje, ale táto hodnota tam neni, pridaj ju
+ if (found === false){
+ device.data.push({
+ "changed": true,
+ "name": com.tb_name,
+ "value": v
+ });
+ }
+ }
+
+ //Správne sme prijali odpoveď, je čas na další msg
+ startCmdWaitInterval();
+ }
+ //console.log('received data array', receivedDataArray);
+ receivedDataArray = [];
+ }
+
+ function updateDataInTB(){
+ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index];
+
+ // console.log("---- MB device", device);
+ // console.log("---MB device data", device.data);
+
+ let values = "";
+ for (let i = 0; i < device.data.length; i++){
+ let data = device.data[i];
+ if (data.changed){
+ if (values !== ""){
+ values += ", ";
+ }
+
+ if (data.name === "status"){
+ values += "\""+data.name+"\":\""+data.value+"\"";
+ // This makes sure, that if this device doesn’t respond even once in next reading cycle, it will be marked as NOK
+ device.data[i].changed = true;
+ device.data[i].value = "NOK";
+ } else {
+ values += "\""+data.name+"\":"+data.value;
+ device.data[i].changed = false;
+ }
+ }
+
+ }
+
+ //console.log("values modbus", values);
+
+
+ if (values !== ""){
+
+ // let tbname = FLOW.OMS_edgeName;
+ // if(tbname == "" || tbname === undefined )
+ // {
+ // console.log("!!!!!!FLOW.OMS_edgeName is empty - 1");
+ // return;
+ // }
+
+ let tbmsg = "{\"" + tbname + "\":[{\"ts\":"+Date.now()+", \"values\":{"+values+"}}] }";
+ tbmsg = JSON.parse(tbmsg);
+
+ values = tbmsg[tbname][0]["values"];
+
+ //console.log("modbus", Object.keys(values));
+
+ //sum Phase_1_power, Phase_2_power, Phase_3_power (if one of them is undefined, we handle it)
+ const numOr0 = n => isNaN(n) ? 0 : n;
+ let calculated_total_power = [values["Phase_1_power"], values["Phase_2_power"], values["Phase_3_power"]].reduce((a, b) => numOr0(a) + numOr0(b));
+ values["total_power"] = parseFloat(calculated_total_power.toFixed(2));
+ tbmsg[tbname][0]["values"] = values;
+
+ Object.keys(values).map(singleValue => {
+ if (["Phase_1_voltage", "Phase_2_voltage", "Phase_3_voltage"].includes(singleValue))
+ {
+
+ let l = singleValue.split("_");
+ let phase = parseInt(l[1]);
+
+ if(FLOW.OMS_no_voltage == undefined) FLOW.OMS_no_voltage = new Set();
+
+ if(values[singleValue] == 0)
+ {
+ sendNotification("modbus_citys: updateDataInTB", tbname, "no_voltage_detected_on_phase", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase );
+
+ FLOW.OMS_no_voltage.add(phase);
+ }
+ else
+ {
+ FLOW.OMS_no_voltage.delete(phase);
+ sendNotification("modbus_citys: updateDataInTB", tbname, "voltage_on_phase_has_been_restored", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase);
+ }
+
+ }
+ })
+
+ sendThingsBoard(tbmsg);
+ }
+ }
+
+
+ let electrometerNotResponding = 0;
+ function sendCommand(){
+ let device = PRIVATEVARS.devices[PRIVATEVARS.device_index];
+ let com = device.cmd[PRIVATEVARS.cmd_index];
+ let array = [device.address, 3, ((com.register >> 8) & 0xFF), (com.register & 0xFF), ((com.size >> 8) & 0xFF), (com.size & 0xFF)];
+ array = modbusCRC(array);
+
+ //console.log('---device--', device);
+ //console.log('---device type--', device.type);
+
+ //sendError("sendCommand", device.tb_name, ERRWEIGHT.DEBUG, "Sending command !", {"cmd": array});
+ //console.log("sendCommand", device.tb_name, ERRWEIGHT.DEBUG, "Sending command !", {"cmd": array});
+
+ // let tbname = FLOW.OMS_edgeName;
+ // if(tbname == "" || tbname === undefined )
+ // {
+ // console.log("!!!!!!FLOW.OMS_edgeName is empty - 2");
+ // return;
+ // }
+
+ startTimeoutInterval();
+ port.write(Buffer.from(array), function(err) {
+
+ //! poslany command
+ //console.log("poslany tento commant", array, err, device.type);
+
+ if (err) {
+ stopTimeoutInterval();
+ stopCmdWaitInterval();
+
+
+ // elektromer neodpoveda viac ako 5 minut (15 commands za minutu sa posiela)
+ if (device.type === "EM111" || device.type === "EM340")
+ {
+ electrometerNotResponding++;
+
+ if (electrometerNotResponding > 15 && electrometerNotResponding < 17)
+ {
+
+ //sendError("Modbus_citys: sendCommand", tbname, ERRWEIGHT.CRITICAL, "Electrometer is not responding", {"err": err.message, "info": "No response more than 5 minutes"});
+ sendNotification("modbus_citys: sendCommand", tbname, "electrometer_is_not_responding", {}, {"err": err.message, "info": "No response more than 5 minutes"}, instanceSendTo.tb, instance );
+
+ let tbmsg = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": {
+ "status": "NOK"
+ }
+ }
+ ]
+ }
+
+ sendThingsBoard(tbmsg)
+ }
+ }
+
+
+ return;
+ }
+
+ if (device.type === "EM111")
+ {
+ if (electrometerNotResponding > 15)
+ {
+ //sendError("Modbus_citys: sendCommand", tbname, ERRWEIGHT.NOTICE, "Electrometer is responding again", "");
+ sendNotification("modbus_citys: sendCommand", tbname, "electrometer_is_responding_again", {}, "", instanceSendTo.tb, instance );
+ }
+ electrometerNotResponding = 0;
+
+ }
+ });
+ }
+
+ function modbusCRC(array){
+ let crc = 0xFFFF;
+ for (let i = 0; i < array.length; i++){
+ let b = array[i];
+ crc = crc ^ b;
+
+ for (let j = 8; j>0; j--){
+ if ((crc & 0x0001) != 0){
+ crc = crc >> 1;
+ crc = crc ^ 0xA001;
+ } else {
+ crc = crc >> 1;
+ }
+ }
+ }
+
+ array.push(crc & 0xFF);
+ array.push((crc >> 8) & 0xFF);
+
+ return array;
+ }
+
+
+ instance.on('data', function(flowdata) {
+
+ console.log("flowdata on data", flowdata);
+ sendStatus({"CONFIG": instance.CONFIG, "PRIVATEVARS":PRIVATEVARS})
+
+ });
+
+ instance.reconfigure = function() {
+
+ //TODO remove ftom options
+ myEdge = instance.options.edge;
+ if (starter === null){
+ starter = setInterval(function(){
+ loadData();
+ clearInterval(starter);
+ starter = null;
+ }, 5000);
+ }
+ };
+
+ instance.close = function() {
+ // close sockets and such
+ };
+
+ function sendError(func, device, weight, str, extra){
+ if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
+ return; // Allow debug messages only if CONFIG.debug is active
+ }
+
+ let content = {
+ "type": weight,
+ "status": "new",
+ "source": {
+ "func":func,
+ "component":instance.id,
+ "component_name":instance.name,
+ "edge":myEdge
+ },
+ "message":str,
+ "message_data": extra
+ };
+ let msg = {};
+ msg[device] = [
+ {
+ "ts": Date.now(),
+ "values": {
+ "_event":content
+ }
+ }
+ ];
+
+ // Msg can be outputted from components only after configuration
+ /*if (canSendErrData()){
+ sendBufferedErrors();
+ } else {
+ bufferError(msg);
+ }*/
+ instance.send(instanceSendTo.tb, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
+
+
+
+ function sendBufferedErrors(){
+ if (PRIVATEVARS.errBuffer === undefined){
+ console.log("errBuffer undefined");
+ console.log("private: ", PRIVATEVARS);
+ }
+ console.log("errBuffer size: ", PRIVATEVARS.errBuffer.length);
+ if (PRIVATEVARS.errBuffer.length > 0){
+ for (let i = 0; i < PRIVATEVARS.errBuffer.length; i++){
+ instance.send(instanceSendTo.error, PRIVATEVARS.errBuffer[i]);
+ }
+ PRIVATEVARS.errBuffer = []; //Clear the buffer
+ saveData();
+ }
+ }
+
+ function bufferError(msg){
+ PRIVATEVARS.errBuffer.push(msg);
+ saveData();
+ }
+ }
+
+ function canSendErrData(){
+ //if (FLOW.errServerAvailable)
+ return true;
+ //else
+ // return false;
+ }
+
+ function sendStatus(str){
+ instance.send(instanceSendTo.debug, str);
+ }
+
+ function sendThingsBoard(obj){
+ // Msg can be outputted from components only after configuration
+ /*if (canSendTbData()){
+ sendBufferedTB();
+ } else {
+ console.log("cant send data");
+ bufferTB(str);
+ }*/
+ //console.log("send thingsboard", str);
+
+ //console.log("FLOW.OMS_edgeName", FLOW.OMS_edgeName, obj);
+
+ if(obj.hasOwnProperty(FLOW.OMS_edgeName) && FLOW.OMS_edgeName != "")
+ {
+ //send it to di_do_controller
+ instance.send(instanceSendTo.di_do_controller, {sender: "modbus_citysys", tbdata: obj});
+ }
+ // else
+ {
+ instance.send(instanceSendTo.tb, obj); // Even if TB server is unavailable, send this message to output, for other possible component connections
+ }
+
+ //instance.send(2, str); // Even if TB server is unavailable, send this message to output, for other possible component connections
+
+
+ function sendBufferedTB(){
+ if (PRIVATEVARS.tbBuffer.length > 0){
+ console.log("sending buffered: ", PRIVATEVARS.tbBuffer.length );
+ for (let i = 0; i < PRIVATEVARS.tbBuffer.length; i++){
+ instance.send(instanceSendTo.tb, PRIVATEVARS.tbBuffer[i]);
+ }
+ PRIVATEVARS.tbBuffer = []; //Clear the buffer
+ saveData();
+ }
+ }
+
+ function bufferTB(str){
+ PRIVATEVARS.tbBuffer.push(str);
+ saveData();
+ }
+ }
+
+ function canSendTbData(){
+ //if (FLOW.tbAvailable)
+ return true;
+ //else
+ // return false;
+ }
+
+ function startTimeoutInterval(){
+ if (!timeoutInterval){
+ timeoutInterval = setInterval(readingTimeouted, instance.CONFIG.timeoutTime);
+ }
+ }
+
+ function stopTimeoutInterval(){
+ if (timeoutInterval){
+ clearInterval(timeoutInterval);
+ timeoutInterval = null;
+ }
+ }
+
+ function startCmdWaitInterval(){
+ if (!msgWaitInterval){
+ msgWaitInterval = setInterval(readDeviceData, instance.CONFIG.msgWaitTime);
+ }
+ }
+
+ function stopCmdWaitInterval(){
+ if (msgWaitInterval){
+ clearInterval(msgWaitInterval);
+ msgWaitInterval = null;
+ }
+ }
+
+ instance.on('options', instance.reconfigure);
+ instance.reconfigure();
+
+ // LAST SECTION FOR COMMON FUNCTIONS
+ function humanReadableTimeAndDate(){
+ let date_ob = new Date();
+
+ let date = ("0" + date_ob.getDate()).slice(-2);
+ let month = ("0" + (date_ob.getMonth() + 1)).slice(-2);
+ let year = date_ob.getFullYear();
+
+ let hours = ("0" + date_ob.getHours()).slice(-2);
+ let minutes = ("0" + date_ob.getMinutes()).slice(-2);
+ let seconds = ("0" + date_ob.getSeconds()).slice(-2);
+
+ return date+"."+month+"."+year+" "+hours+":"+minutes+":"+seconds;
+ }
+
+ if (starter === null){
+ starter = setInterval(function(){
+ loadData();
+ clearInterval(starter);
+ starter = null;
+ }, 5000);
+ }
+
+ //setTimeout(loadData, 5000);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js
deleted file mode 100644
index f34ec9a..0000000
--- a/flow/modbus_reader.js
+++ /dev/null
@@ -1,348 +0,0 @@
-exports.id = 'modbus_reader';
-exports.title = 'Modbus reader';
-exports.version = '2.0.0';
-exports.group = 'Worksys';
-exports.color = '#2134B0';
-exports.output = ["red", "white", "yellow"];
-exports.click = false;
-exports.author = 'Rastislav Kovac';
-exports.icon = 'bolt';
-exports.readme = `
- Modbus requests to modbus devices (electromer, twilight sensor, thermometer.
- Component keeps running arround deviceConfig array in "timeoutInterval" intervals. Array items are objects with single modbus devices.
- Everything is sent to dido_controller. If requests to device fail (all registers must fail to send NOK status) , we send "NOK-'device'" status to dido_controller.
- This device needs to be configured in dido_controller!!! Double check if it is. In dido_controller we calculate final status and all values with status are pushed to tb.
-`;
-
-const modbus = require('jsmodbus');
-const SerialPort = require('serialport');
-const { timeoutInterval, deviceConfig } = require("../databases/modbus_config");
-const { sendNotification } = require('./helper/notification_reporter');
-
-const DELAY_BETWEEN_DEVICES = 10000;
-
-const SEND_TO = {
- debug: 0,
- dido_controller: 1,
- tb: 2
-};
-
-//to handle NOK and OK sendNotifications s
-const numberOfNotResponding = {};
-let tbName = null;
-let mainSocket;
-
-
-exports.install = function(instance) {
-
- class SocketWithClients {
-
- constructor () {
- this.stream = null;
- this.socket = null;
- this.clients = {};
- this.allValues = {};
- this.errors = 0;
- this.index = 0;
- this.timeoutInterval = 5000;
-
- // we need to go always around for all devices. So we need index value, device address, as well as number of registers for single device
- this.deviceAddress = null; // device address (1 - EM340 and 2 for twilight_sensor)
- this.indexInDeviceConfig = 0; // first item in deviceConfig
- this.lengthOfActualDeviceStream = null;
- this.device = null;
-
- // lampSwitchNotification helper variables
- this.onNotificationSent = false;
- this.offNotificationSent = false;
-
- this.startSocket();
- }
-
- startSocket = () => {
-
- let obj = this;
-
- this.socket = new SerialPort("/dev/ttymxc0", {
- baudRate: 9600,
- })
-
- // we create a client for every deviceAddress ( = address) in list and push them into dictionary
- for( let i = 0; i < deviceConfig.length; i++)
- {
- this.clients[deviceConfig[i].deviceAddress] = new modbus.client.RTU(this.socket, deviceConfig[i].deviceAddress, 2000); // 2000 is timeout in register request, default is 5000, which is too long
- }
-
- this.socket.on('error', function(e) {
- console.log('socket connection error', e);
- if(e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
- console.log(exports.title + ' Waiting 10 seconds before trying to connect again');
- setTimeout(obj.startSocket, 10000);
- }
- });
-
- this.socket.on('close', function() {
- console.log('Socket connection closed ' + exports.title + ' Waiting 10 seconds before trying to connect again');
- setTimeout(obj.startSocket, 10000);
- });
-
- this.socket.on('open', function () {
- console.log("socket connected");
- obj.getActualStreamAndDevice();
- obj.timeoutInterval = timeoutInterval - DELAY_BETWEEN_DEVICES; // to make sure readout always runs in timeoutinterval we substract DELAY_BETWEEN_DEVICES
- })
-
- };
-
- getActualStreamAndDevice = () => {
- const dev = deviceConfig[this.indexInDeviceConfig];
- this.index = 0;
- this.errors = 0;
- this.stream = dev.stream;
- this.lengthOfActualDeviceStream = dev.stream.length;
- this.deviceAddress = dev.deviceAddress; // 1 or 2 or any number
- this.device = dev.device; //em340, twilight_sensor
-
- if(this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval);
- else setTimeout(this.readRegisters, DELAY_BETWEEN_DEVICES);
- }
-
- readRegisters = () => {
-
- const str = this.stream[this.index];
- const register = str.register;
- const size = str.size;
- const tbAttribute = str.tbAttribute;
-
- let obj = this;
-
- this.clients[this.deviceAddress].readHoldingRegisters(register, size)
- .then( function (resp) {
-
- resp = resp.response._body.valuesAsArray; //resp is array of length 1 or 2, f.e. [2360,0]
- // console.log(deviceAddress, register, tbAttribute, resp);
-
- //device is responding again after NOK status
- if(numberOfNotResponding.hasOwnProperty(obj.device))
- {
- let message = "";
- if(obj.device == "em340")
- {
- message = "electrometer_ok";
- }
- else if(obj.device == "twilight_sensor")
- {
- message = "twilight_sensor_ok";
- }
- message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", SEND_TO.tb, instance);
- delete numberOfNotResponding[obj.device];
- }
-
- obj.transformResponse(resp, register);
-
- //obj.errors = 0;
- obj.index++;
- obj.readAnotherRegister();
-
- }).catch (function () {
-
- console.log("errors pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute);
-
- obj.errors++;
- if(obj.errors == obj.lengthOfActualDeviceStream)
- {
- instance.send(SEND_TO.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
-
- //todo - neposlalo notification, ked sme vypojili twilight a neposle to do tb, ale do dido ??
- if(!numberOfNotResponding.hasOwnProperty(obj.device))
- {
- let message = "";
- if(obj.device == "twilight_sensor")
- {
- message = "twilight_sensor_nok";
- }
- else if(obj.device == "em340")
- {
- message = "electrometer_nok";
- }
- message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", SEND_TO.tb, instance);
- numberOfNotResponding[obj.device] = 1;
- }
-
- obj.errors = 0;
- numberOfNotResponding[obj.device] += 1;
- }
-
- console.error(require('util').inspect(arguments, {
- depth: null
- }))
-
- // if reading out of device's last register returns error, we send accumulated allValues to dido_controller (if allValues are not an empty object)
- if(obj.index + 1 >= obj.lengthOfActualDeviceStream)
- {
- if(!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, {values: obj.allValues});
- obj.allValues = {};
- }
- obj.index++;
- obj.readAnotherRegister();
- })
-
- };
-
- readAnotherRegister = () => {
- if(this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0);
- else this.setNewStream();
- }
-
- transformResponse = (response, register) => {
-
- for (let i = 0; i < this.lengthOfActualDeviceStream; i++) {
-
- let a = this.stream[i];
- if (a.register === register)
- {
- let tbAttribute = a.tbAttribute;
- let multiplier = a.multiplier;
-
- let value = this.calculateValue(response, multiplier);
- // console.log(register, tbName, tbAttribute, response, a.multiplier, value);
-
- // if(tbName == undefined) return;
-
- if(this.index + 1 < this.lengthOfActualDeviceStream)
- {
- this.allValues[tbAttribute] = value;
- return;
- }
-
- const values = {
- ...this.allValues,
- [tbAttribute]: value,
- };
-
- this.checkNullVoltage(values);
- this.lampSwitchNotification(values);
-
- instance.send(SEND_TO.dido_controller, {values: values});
-
- this.allValues = {};
- break;
- }
-
- }
-
- }
-
- setNewStream = () =>
- {
- if(this.lengthOfActualDeviceStream == this.index)
- {
- if(this.indexInDeviceConfig + 1 == deviceConfig.length)
- {
- this.indexInDeviceConfig = 0;
- }
- else
- {
- this.indexInDeviceConfig += 1;
- }
-
- this.getActualStreamAndDevice();
- }
- }
-
- calculateValue = (response, multiplier) =>
- {
- let value = 0;
-
- let l = response.length;
- if (l === 2)
- {
- value = (response[1]*(2**16) + response[0]);
-
- if(value >= (2**31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x80000000), ak vieš robiť logický súčin
- {
- value = value - "0xFFFFFFFF" + 1;
- }
- }
- else if (l === 1)
- {
- value = response[0];
-
- if(value >= (2**15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (value & 0x8000), ak vieš robiť logický súčin
- {
- value = value - "0xFFFF" + 1;
- }
- }
-
- return Math.round(value * multiplier * 10) / 10;
- }
-
- checkNullVoltage = (values) => {
-
- if(!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
-
- Object.keys(values).map(singleValue => {
- if (["Phase_1_voltage", "Phase_2_voltage", "Phase_3_voltage"].includes(singleValue))
- {
- let l = singleValue.split("_");
- let phase = parseInt(l[1]);
-
- if(FLOW.OMS_no_voltage == undefined) FLOW.OMS_no_voltage = new Set();
- // console.log(values[singleValue], tbName);
-
- if(values[singleValue] == 0)
- {
- FLOW.OMS_no_voltage.add(phase);
- sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase );
- // console.log('no voltage')
- }
- else
- {
- FLOW.OMS_no_voltage.delete(phase);
- // console.log('voltage detected')
- sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase);
- }
- }
- })
- }
-
- /**
- * function sends notification to slack and to tb, if EM total_power value changes more than 500. This should show, that RVO lamps has been switched on or off
- */
- lampSwitchNotification = (values) => {
-
- if(!values.hasOwnProperty("total_power")) return;
-
- const actualTotalPower = values.total_power;
- if(actualTotalPower > 600 && this.onNotificationSent == false)
- {
- sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_on", {}, "", SEND_TO.tb, instance);
- this.onNotificationSent = true;
- this.offNotificationSent = false;
- }
- else if(actualTotalPower <= 600 && this.offNotificationSent == false)
- {
- sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_off", {}, "", SEND_TO.tb, instance);
- this.onNotificationSent = false;
- this.offNotificationSent = true;
- }
- }
-
- }
-
- const isObjectEmpty = (objectName) => {
- return Object.keys(objectName).length === 0 && objectName.constructor === Object;
- }
-
- setTimeout(() => {
-
- mainSocket = new SocketWithClients();
- tbName = FLOW.OMS_rvo_tbname;
-
- // this notification is to show, that flow (unipi) has been restarted
- sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance);
-
- }, 25000);
-
-}
-
diff --git a/flow/monitorcpu.js b/flow/monitorcpu.js
new file mode 100644
index 0000000..0e906d1
--- /dev/null
+++ b/flow/monitorcpu.js
@@ -0,0 +1,107 @@
+exports.id = 'monitorcpu';
+exports.title = 'CPU';
+exports.version = '1.0.0';
+exports.author = 'Peter Širka';
+exports.group = 'Monitoring';
+exports.color = '#F6BB42';
+exports.output = 1;
+exports.icon = 'microchip';
+exports.options = { enabled: true };
+exports.click = true;
+exports.readme = `# CPU monitoring
+
+This component monitors CPU \`% percentage\` consumption in Linux systems. It uses \`mpstat\` command.
+
+__Data Example__:
+
+\`\`\`javascript
+{
+ cpu: 30, // percentage
+ cores: [4, 60, 0], // percentage
+ count: 3 // count of cores
+}
+\`\`\``;
+
+exports.html = `
+
+
+
@(Interval in milliseconds)
+
+
+
`;
+
+exports.install = function(instance) {
+
+ var fields = ['CPU', '%idle'];
+ var current = { cores: [], cpu: 0, count: 0 };
+ var proc = null;
+ var tproc = null;
+
+ instance.custom.kill = function() {
+ if (proc) {
+ proc.kill('SIGKILL');
+ proc = null;
+ }
+ };
+
+ instance.custom.run = function() {
+
+ if (tproc) {
+ clearTimeout(tproc);
+ tproc = null;
+ }
+
+ instance.custom.kill();
+ proc = require('child_process').spawn('mpstat', ['-P', 'ALL', 10]);
+ proc.stdout.on('data', U.streamer('\n\n', instance.custom.process));
+ proc.stdout.on('error', function(e) {
+ instance.error(e);
+ instance.custom.kill();
+ tproc = setTimeout(instance.custom.run, instance.options.interval || 5000);
+ });
+ };
+
+ instance.custom.process = function(chunk) {
+ current.cpu = 0;
+ chunk.toString('utf8').parseTerminal(fields, instance.custom.parse);
+ current.count = current.cores.length;
+ if (current.count) {
+ instance.send2(current);
+ instance.custom.status();
+ }
+ };
+
+ instance.custom.parse = function(values) {
+ var val = 100 - values[1].parseFloat2();
+ if (values[0] === 'all')
+ current.cpu = val;
+ else
+ current.cores[+values[0]] = val;
+ };
+
+ instance.custom.status = function() {
+ if (instance.options.enabled)
+ instance.status(current.cpu.floor(1) + '%');
+ else
+ instance.status('Disabled', 'red');
+ };
+
+ instance.on('click', function() {
+ instance.options.enabled = !instance.options.enabled;
+ instance.custom.status();
+ if (instance.options.enabled)
+ instance.custom.run();
+ else
+ instance.custom.kill();
+ });
+
+ instance.on('close', function() {
+ instance.custom.kill();
+ if (tproc) {
+ clearTimeout(tproc);
+ tproc = null;
+ }
+ });
+
+ setTimeout(instance.custom.run, 1000);
+};
\ No newline at end of file
diff --git a/flow/mqtt.js b/flow/mqtt.js
new file mode 100644
index 0000000..e34c940
--- /dev/null
+++ b/flow/mqtt.js
@@ -0,0 +1,441 @@
+exports.id = 'mqtt';
+exports.title = 'MQTT broker';
+exports.group = 'MQTT';
+exports.color = '#888600';
+exports.version = '1.0.1';
+exports.icon = 'exchange';
+exports.input = true;
+exports.output = 0;
+exports.author = 'Martin Smola';
+exports.variables = true;
+exports.options = { host: '127.0.0.1', port: 1883 };
+exports.traffic = false;
+exports.npm = ['mqtt'];
+
+exports.html = `
+
+
+
Hostname or IP address
+
+
+
+
+
+
@(Client id)
+
@(Supports variables, example: \`client_{device-id}\`)
+
@(Secure (ssl))
+
+
+
+
+
+
@(Require Authorization)
+
+
+
+
+
+
+
+
@(Last will topic)
+
@(Supports variables, example: \`lwt/{device-id}\`)
+
+
+
@(Last will message)
+
@(Supports variables, example: \`{device-id} is offline\`)
+
+
+
+`;
+
+exports.readme = `
+# MQTT Broker
+
+## Input
+Allows to change connection programaticaly
+\`\`\`javascipt
+{
+ host: '1.2.3.4',
+ port: '',
+ secure: true/false,
+ username: 'john',
+ password: 'X',
+ lwttopic: '',
+ lwtmessage: '',
+ clientid: ''
+}
+\`\`\`
+`;
+
+var MQTT_BROKERS = [];
+var mqtt;
+
+global.MQTT = {};
+
+exports.install = function(instance) {
+
+ var broker;
+
+ mqtt = require('mqtt');
+
+ instance.on('data', function(flowdata){
+ var data= flowdata.data;
+ var options = instance.options;
+
+ if (data.host && data.port)
+ return instance.custom.reconfigure(data, options);
+
+ if (data.close === true)
+ instance.close(NOOP);
+ });
+
+ instance.custom.reconfigure = function(o, old_options) {
+
+ if (old_options)
+ MQTT_BROKERS = MQTT_BROKERS.remove(function(b){
+ return b.id === old_options.id;
+ });
+
+ var options = instance.options;
+
+ if (!options.host || !options.port) {
+ instance.status('Not configured', 'red');
+ return;
+ }
+
+ options.id = (options.username || '') + '@' + options.host + ':' + options.port;
+
+ if (broker) {
+ broker.close();
+ EMIT('mqtt.brokers.status', 'reconfigured', old_options.id, options.id);
+ }
+
+ instance.custom.createBroker();
+ };
+
+ instance.custom.createBroker = function() {
+
+ ON('mqtt.brokers.status', brokerstatus);
+
+ var o = instance.options;
+ var opts = {
+ host: o.host,
+ port: o.port,
+ id: o.id,
+ secure: o.secure,
+ rejectUnauthorized: false,
+ reconnectPeriod: 3000,
+ resubscribe: false
+ };
+
+ if (o.auth) {
+ opts.username = o.username;
+ opts.password = o.password;
+ }
+
+ if (o.lwt) {
+ opts.will = {
+ topic: instance.arg(o.lwttopic),
+ payload: instance.arg(o.lwtmessage)
+ }
+ }
+
+ if (o.clientid)
+ opts.clientId = instance.arg(o.clientid);
+
+ broker = new Broker(opts);
+ MQTT_BROKERS.push(broker);
+
+ instance.status('Ready');
+ };
+
+ instance.close = function(done) {
+
+ broker && broker.close(function() {
+ MQTT_BROKERS = MQTT_BROKERS.remove('id', instance.options.id);
+ EMIT('mqtt.brokers.status', 'removed', instance.options.id);
+ });
+
+ OFF('mqtt.brokers.status', brokerstatus);
+
+ done();
+ };
+
+ function brokerstatus(status, brokerid, err) {
+ if (brokerid !== instance.options.id)
+ return;
+
+ switch (status) {
+ case 'connecting':
+ instance.status('Connecting', '#a6c3ff');
+ break;
+ case 'connected':
+ instance.status('Connected', 'green');
+ break;
+ case 'disconnected':
+ instance.status('Disconnected', 'red');
+ break;
+ case 'connectionfailed':
+ instance.status('Connection failed', 'red');
+ break;
+ case 'error':
+ instance.error('MQTT Error, ID: ' + instance.id + '\n ' + err);
+ break;
+ }
+ }
+
+ instance.on('options', instance.custom.reconfigure);
+ instance.custom.reconfigure();
+};
+
+FLOW.trigger('mqtt.brokers', function(next) {
+ var brokers = [''];
+ MQTT_BROKERS.forEach(n => brokers.push(n.id));
+ next(brokers);
+});
+
+MQTT.add = function(brokerid, componentid) {
+ var broker = MQTT_BROKERS.findItem('id', brokerid);
+
+ if (broker)
+ broker.add(componentid);
+};
+
+MQTT.remove = function(brokerid, componentid) {
+ var broker = MQTT_BROKERS.findItem('id', brokerid);
+ broker && broker.remove(componentid);
+};
+
+MQTT.publish = function(brokerid, topic, data, options) {
+ var broker = MQTT_BROKERS.findItem('id', brokerid);
+ if (broker)
+ broker.publish(topic, data, options);
+ else
+ EMIT('mqtt.brokers.status', 'error', brokerid, 'No such broker');
+};
+
+MQTT.subscribe = function(brokerid, componentid, topic, qos) {
+ var broker = MQTT_BROKERS.findItem('id', brokerid);
+
+ if (!broker)
+ return;
+
+ broker.add(componentid);
+ broker.subscribe(componentid, topic, qos);
+};
+
+MQTT.unsubscribe = function(brokerid, componentid, topic, qos) {
+ var broker = MQTT_BROKERS.findItem('id', brokerid);
+ if (!broker)
+ return;
+
+ broker.unsubscribe(componentid, topic);
+ broker.remove(componentid);
+};
+
+MQTT.broker = function(brokerid) {
+ return MQTT_BROKERS.findItem('id', brokerid);
+};
+
+/*
+
+ https://github.com/mqttjs/MQTT.js/blob/master/examples/client/secure-client.js
+
+*/
+
+/*
+ TODO
+
+ - add `birth` and `last will and testament` messages
+ - add options to self.client.connect(broker [,options]); - credentials, certificate etc.
+
+
+*/
+
+function Broker(options) {
+ var self = this;
+
+ if (!options.host || !options.port)
+ return false;
+
+ self.connecting = false;
+ self.connected = false;
+ self.closing = false;
+ self.components = [];
+ self.subscribtions = {};
+ self.id = options.id;
+ self.options = options;
+ setTimeout(function() {
+ EMIT('mqtt.brokers.status', 'new', self.id);
+ }, 500);
+ return self;
+}
+
+Broker.prototype.connect = function() {
+
+ var self = this;
+ if (self.connected || self.connecting)
+ return EMIT('mqtt.brokers.status', self.connected ? 'connected' : 'connecting', self.id);
+
+ self.connecting = true;
+ var broker = self.options.secure ? 'mqtts://' : 'mqtt://' + self.options.host + ':' + self.options.port;
+
+ EMIT('mqtt.brokers.status', 'connecting', self.id);
+
+ self.client = mqtt.connect(broker, self.options);
+
+ self.client.on('connect', function() {
+ self.connecting = false;
+ self.connected = true;
+ if (self.reconnecting) {
+ EMIT('mqtt.brokers.status', 'reconnected', self.id);
+ self.reconnecting = false;
+ self.resubscribe();
+ }
+ EMIT('mqtt.brokers.status', 'connected', self.id);
+ });
+
+ self.client.on('reconnect', function() {
+ self.connecting = true;
+ self.connected = false;
+ self.reconnecting = true;
+ EMIT('mqtt.brokers.status', 'connecting', self.id);
+ });
+
+ self.client.on('message', function(topic, message) {
+ message = message.toString();
+ if (message[0] === '{') {
+ TRY(function() {
+ message = JSON.parse(message);
+ }, () => FLOW.debug('MQTT: Error parsing data', message));
+ }
+ EMIT('mqtt.brokers.message', self.id, topic, message);
+ });
+
+ self.client.on('close', function(err) {
+ if (err && err.toString().indexOf('Error')) {
+ self.connecting = false;
+ self.connected = false;
+ EMIT('mqtt.brokers.status', 'error', self.id, err.code);
+ }
+
+ if (self.connected || !self.connecting) {
+ self.connected = false;
+ EMIT('mqtt.brokers.status', 'disconnected', self.id);
+ } else if (self.connecting) {
+ self.connecting = false;
+ EMIT('mqtt.brokers.status', 'connectionfailed', self.id);
+ }
+ });
+
+ self.client.on('error', function(err) {
+
+ if (self.connecting) {
+ self.client.end();
+ self.connecting = false;
+ EMIT('mqtt.brokers.status', 'error', self.id, err);
+ }
+ });
+
+};
+
+Broker.prototype.disconnect = function(reconnect) {
+ var self = this;
+ if (!self.closing)
+ self.close(function(){
+ reconnect && self.connect();
+ });
+};
+
+Broker.prototype.close = function(callback) {
+ var self = this;
+ self.closing = true;
+
+ if ((self.connected || self.connecting) && self.client && self.client.end)
+ self.client.end(true, cb);
+ else
+ cb();
+
+ function cb() {
+ EMIT('mqtt.brokers.status', 'disconnected', self.id);
+ self.client && self.client.removeAllListeners();
+ self.components = [];
+ self.client = null;
+ callback && callback();
+ }
+};
+
+Broker.prototype.subscribe = function(componentid, topic) {
+ var self = this;
+ self.subscribtions[topic] = self.subscribtions[topic] || [];
+ if (self.subscribtions[topic].indexOf(componentid) > -1)
+ return;
+ self.client.subscribe(topic);
+ self.subscribtions[topic].push(componentid);
+};
+
+Broker.prototype.resubscribe = function() {
+ var self = this;
+ var topics = Object.keys(self.subscribtions);
+ for (var i = 0; i < topics.length; i++)
+ self.client.subscribe(topics[i]);
+};
+
+Broker.prototype.unsubscribe = function(componentid, topic) {
+ var self = this;
+ var sub = self.subscribtions[topic];
+ if (sub) {
+ self.subscribtions[topic] = sub.remove(componentid);
+ self.client.connected && !self.subscribtions[topic].length && self.client.unsubscribe(topic);
+ }
+};
+
+Broker.prototype.publish = function(topic, data, options) {
+ var self = this;
+ if (!self.connected)
+ return;
+
+ if (typeof(data) === 'object') {
+ options.qos = parseInt(data.qos || options.qos);
+ options.retain = data.retain || options.retain;
+ topic = data.topic || topic;
+ data.payload && (data = typeof(data.payload) === 'string' ? data.payload : JSON.stringify(data.payload));
+ }
+
+ if (options.qos !== 0 || options.qos !== 1 || options.qos !== 2)
+ options.qos = null;
+
+ if (typeof(data) !== 'string')
+ data = JSON.stringify(data);
+
+ self.client.publish(topic, data || '', options);
+};
+
+Broker.prototype.add = function(componentid) {
+ var self = this;
+ self.components.indexOf(componentid) === -1 && self.components.push(componentid);
+ self.connect();
+};
+
+Broker.prototype.remove = function(componentid) {
+ var self = this;
+ self.components = self.components.remove(componentid);
+ !self.components.length && self.disconnect();
+};
diff --git a/flow/mqtt_listener.js b/flow/mqtt_listener.js
new file mode 100644
index 0000000..b9d778d
--- /dev/null
+++ b/flow/mqtt_listener.js
@@ -0,0 +1,171 @@
+exports.id = 'mqttlistener';
+exports.title = 'MQTT listener';
+exports.group = 'MQTT';
+exports.color = '#888600';
+exports.version = '1.0.0';
+exports.icon = 'sign-out';
+exports.input = 1;
+exports.output = ["red", "white"];
+exports.author = 'Rastislav Kovac';
+exports.options = { host: "", port: 1883, clientid: "", username: "" };
+//exports.npm = ['mqtt', 'streamroller'];
+
+
+exports.html = `
+
+
+
Hostname or IP address
+
+
+
+
+
`;
+
+
+exports.readme = `
+# MQTT processor
+
+Version 1.0.0
+
+It serves as a client and subscribes to 'rpc' topic. It receives rpc calls from kovobel-prod01, which receives it from platform.
+
+`;
+
+const instanceSendTo = {
+ debug: 0,
+ rpcCall: 1,
+}
+
+
+exports.install = function(instance) {
+
+
+ const mqtt = require("mqtt");
+
+ instance.on('options', loadNodes);
+
+
+ function loadNodes()
+ {
+
+ if(instance.options.host == "")
+ {
+ instance.status('No configuration', 'red');
+ }
+ else
+ {
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ rejectUnauthorized: false,
+ resubscribe: true
+ };
+
+ connectToServer();
+
+ }
+
+ }
+
+ function connectToServer()
+ {
+ var url = "mqtt://" + opts.host + ":" + opts.port;
+ console.log("MQTT URL: ", url);
+
+ client = mqtt.connect(url, opts);
+
+ client.on('connect', function() {
+ instance.status("Connected", "green");
+ client.subscribe('rpc', function (err) {
+ if (!err) {
+ client.publish('rpc', 'Hello mqtt');
+ console.log('message published');
+ }
+ });
+ });
+
+ client.on('reconnect', function() {
+ instance.status("Reconnecting", "yellow");
+ });
+
+ client.on('message', function(topic, message) {
+ // message is type of buffer
+ message = message.toString();
+
+ // instance.send(1, message);
+ // return;
+
+ if (message[0] === '{') {
+
+ try {
+ message = JSON.parse(message);
+
+ if (Object.keys(message).length < 2 || !Object.keys(message).includes("message")) return;
+
+ message.message = JSON.parse(message.message);
+ instance.send(instanceSendTo.rpcCall, message);
+
+ } catch (e) {
+ instance.debug(`MQTT: Error parsing data, ${e}`);
+ }
+ }
+
+ });
+
+ client.on('close', function(err) {
+ if (err && err.toString().indexOf('Error')) {
+ instance.status("Err: "+err.code, "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ } else {
+ instance.status("Disconnected", "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ }
+ });
+
+ client.on('error', function(err) {
+ instance.status("Err: "+ err.code, "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker ERROR signal received !", "error":err, "opt":opts });
+
+ });
+ }
+
+
+ //set opts accortding to options
+ instance.reconfigure = function() {
+
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ rejectUnauthorized: false,
+ resubscribe: true
+ };
+
+ connectToServer();
+ };
+
+ instance.close = function(done) {
+ client.end();
+ };
+
+
+ loadNodes();
+
+ instance.on('options', instance.reconfigure);
+ instance.reconfigure();
+};
+
+
+
diff --git a/flow/mqttprocessor.js b/flow/mqttprocessor.js
new file mode 100644
index 0000000..1bf050c
--- /dev/null
+++ b/flow/mqttprocessor.js
@@ -0,0 +1,317 @@
+exports.id = 'mqttprocessor';
+exports.title = 'MQTT processor';
+exports.group = 'MQTT';
+exports.color = '#888600';
+exports.version = '1.0.0';
+exports.icon = 'sign-out';
+exports.input = 1;
+exports.output = ["red", "white", "blue"];
+exports.author = 'Rastislav Kovac';
+exports.options = { host: "", port: 1883, clientid: "", username: "" };
+//exports.npm = ['mqtt', 'streamroller'];
+
+
+exports.html = `
+
+
+
Hostname or IP address
+
+
+
+
+
`;
+
+
+exports.readme = `
+# MQTT processor
+
+Version 1.0.0
+
+It serves as a client, listens and subscribes to nodes in citysys configuration.
+Is able to send messages to flow (as rpc calls from platform)
+
+Added:
+- database collections,
+- rpc response
+`;
+
+const instanceSendTo = {
+ debug: 0,
+ rpcCall: 1,
+ cmdManager: 2
+}
+
+const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
+const mqtt = require('mqtt');
+
+
+//topics = {joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM: 'lamp_697/brightness'} --> to get topic from dataToTb tb name.
+const topics = {};
+//tbNames = {'lamp_697/brightness': joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM }
+const tbNames = {};
+
+
+exports.install = function(instance) {
+
+ let client = null;
+ let opts = null;
+
+ instance.on('options', loadNodes);
+
+
+ async function loadNodes()
+ {
+ const nodes = TABLE("nodes");
+ let nodesData = await promisifyBuilder(nodes.find());
+
+ nodesData.map(item => {
+ const value = 'lamp_' + item.node + '/brightness';
+ const key = item.tbname;
+ topics[key] = value;
+ tbNames[value] = key;
+ })
+
+ // console.log('******* -------- ', topics);
+ // console.log('******* -------- ', tbNames);
+
+ if(instance.options.host == "")
+ {
+ instance.status('No configuration', 'red');
+ }
+ else
+ {
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ rejectUnauthorized: false,
+ resubscribe: true
+ };
+
+ connectToServer();
+
+ }
+
+ }
+
+ function connectToServer()
+ {
+ var url = "mqtt://" + opts.host + ":" + opts.port;
+ console.log("MQTT URL: ", url);
+
+ client = mqtt.connect(url, opts);
+
+ client.on('connect', function() {
+ instance.status("Connected", "green");
+ // array of subscribed topics ==> Object.values(topics)
+ client.subscribe(Object.values(topics), function (err) {
+ if (!err) {
+ client.publish('presence', 'Hello mqtt');
+ console.log('message published');
+ }
+ });
+ });
+
+ client.on('reconnect', function() {
+ instance.status("Reconnecting", "yellow");
+ });
+
+ client.on('message', function(topic, message) {
+ // message is type of buffer
+ message = message.toString();
+
+ if (message[0] === '{') {
+
+ try {
+ message = JSON.parse(message);
+
+ // we ensure to process messages only with 1 key ==> {'lamp_698/brightness': 20 } and if topic is in topics
+ if (Object.keys(message).length > 1 || !Object.values(topics).includes(topic)) return;
+
+ instance.send(0, {message:message, topic:topic})
+
+ const date = Date.now();
+ const tbName = tbNames[topic];
+
+
+ const transformToRpc = {
+ "topic": "v1/gateway/rpc",
+ "content": {
+ // 'device' is not needed here in 3rd party systems
+ "device": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV",
+ "data": {
+ // 'id' is not needed here
+ "id": 5,
+ "method": "set_command",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "street_luminaire",
+ "tb_name": tbName
+ }
+ ],
+ "command": "dimming",
+ "payload": {
+ "value": message[topic]
+ }
+ }
+ }
+ }
+ }
+
+
+ instance.send(instanceSendTo.cmdManager, transformToRpc);
+
+ } catch (e) {
+ instance.debug(`MQTT: Error parsing data, ${e}`);
+ }
+ }
+
+ });
+
+ client.on('close', function(err) {
+ if (err && err.toString().indexOf('Error')) {
+ instance.status("Err: "+err.code, "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ } else {
+ instance.status("Disconnected", "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ }
+ });
+
+ client.on('error', function(err) {
+ instance.status("Err: "+ err.code, "red");
+ instance.send(instanceSendTo.debug, {"message":"Broker ERROR signal received !", "error":err, "opt":opts });
+
+ });
+ }
+
+
+ //set opts accortding to options
+ instance.reconfigure = function() {
+
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ rejectUnauthorized: false,
+ resubscribe: true
+ };
+
+ connectToServer();
+ };
+
+
+ instance.on('data', function(data) {
+ const value = data.data;
+ const nodeTbName = Object.keys(value)[0];
+
+ // tbnames of all lamps
+ const nodes = Object.values(tbNames);
+
+ if(nodes.includes(nodeTbName))
+ {
+
+ if(value[nodeTbName][0].values.hasOwnProperty('dimming'))
+ {
+ const key = nodeTbName;
+ const tbValues = value[key][0].values;
+
+ Object.keys(tbValues).map(item => {
+ if(item != 'dimming')
+ {
+ delete tbValues[item];
+ }
+ })
+
+ const topic = topics[key];
+ // console.log('---- ***********', key, topic)
+ // console.log('^^^^^^^^^^^^^^', value);
+
+ // transform data to send to 3rd party
+ const v = value[key][0];
+ v[topic] = v.values['dimming'];
+ delete v.values;
+
+ client.publish(topic, JSON.stringify(v));
+ }
+ else if(value[nodeTbName][0].values.hasOwnProperty('status'))
+ {
+ const key = nodeTbName;
+ const tbValues = value[key][0].values;
+
+ Object.keys(tbValues).map(item => {
+ if(item != 'status')
+ {
+ delete tbValues[item];
+ }
+ })
+
+ // we expect topic to be 'lamp_000/brightness'. we must make 'lamp_000/status'
+ const topic = topics[key].slice(0, 8) + '/status';
+ // console.log('---- ***********', key, topic)
+ // console.log('^^^^^^^^^^^^^^', value);
+
+ // transform data to send to 3rd party
+ const v = value[key][0];
+ v[topic] = v.values['status'];
+ delete v.values;
+
+ client.publish(topic, JSON.stringify(v));
+ }
+
+ }
+
+
+
+
+ });
+
+ instance.close = function(done) {
+ client.end();
+ };
+
+
+
+ loadNodes();
+
+ instance.on('options', instance.reconfigure);
+ instance.reconfigure();
+};
+
+
+
+
+/*
+ [ {
+ node: 683,
+ tbname: 'XKQbz3WAwY21dGa0R453rWyJm9PZOjqlvpr6Nkeo',
+ line: 3,
+ profile: '{"intervals":[{"cct":3000,"value":0,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":100,"end_time":"21:20","start_time":"20:00"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"},{"cct":3000,"value":80,"end_time":"22:20","start_time":"21:50"},{"cct":3000,"value":70,"end_time":"22:50","start_time":"22:20"},{"cct":3000,"value":60,"end_time":"23:20","start_time":"22:50"},{"cct":3000,"value":50,"end_time":"23:50","start_time":"23:20"},{"cct":3000,"value":40,"end_time":"00:20","start_time":"23:50"},{"cct":3000,"value":100,"end_time":"05:30","start_time":"03:20"},{"cct":3000,"value":30,"end_time":"00:50","start_time":"00:20"},{"cct":3000,"value":20,"end_time":"01:20","start_time":"00:50"},{"cct":3000,"value":90,"end_time":"21:50","start_time":"21:20"},{"cct":3000,"value":30,"end_time":"01:50","start_time":"01:20"},{"cct":3000,"value":40,"end_time":"02:20","start_time":"01:50"},{"cct":3000,"value":50,"end_time":"02:50","start_time":"02:20"},{"cct":3000,"value":60,"end_time":"03:20","start_time":"02:50"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}',
+ processed: true,
+ status: true
+ },
+ {
+ node: 688,
+ tbname: 'PaGbQ3wBAZWOmRvK9VDpvz5endLJYopEqlkzNMxX',
+ line: 3,
+ profile: '{"intervals":[{"cct":3000,"value":0,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":100,"end_time":"21:20","start_time":"20:00"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"},{"cct":3000,"value":80,"end_time":"22:20","start_time":"21:50"},{"cct":3000,"value":70,"end_time":"22:50","start_time":"22:20"},{"cct":3000,"value":60,"end_time":"23:20","start_time":"22:50"},{"cct":3000,"value":50,"end_time":"23:50","start_time":"23:20"},{"cct":3000,"value":40,"end_time":"00:20","start_time":"23:50"},{"cct":3000,"value":100,"end_time":"05:30","start_time":"03:20"},{"cct":3000,"value":30,"end_time":"00:50","start_time":"00:20"},{"cct":3000,"value":20,"end_time":"01:20","start_time":"00:50"},{"cct":3000,"value":90,"end_time":"21:50","start_time":"21:20"},{"cct":3000,"value":30,"end_time":"01:50","start_time":"01:20"},{"cct":3000,"value":40,"end_time":"02:20","start_time":"01:50"},{"cct":3000,"value":50,"end_time":"02:50","start_time":"02:20"},{"cct":3000,"value":60,"end_time":"03:20","start_time":"02:50"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}',
+ processed: true,
+ status: true
+ }
+]
+*/
+
+
+
diff --git a/flow/mqttpublish.js b/flow/mqttpublish.js
new file mode 100644
index 0000000..3f6aef0
--- /dev/null
+++ b/flow/mqttpublish.js
@@ -0,0 +1,134 @@
+exports.id = 'mqttpublish';
+exports.title = 'MQTT publish';
+exports.group = 'MQTT';
+exports.color = '#888600';
+exports.version = '1.1.0';
+exports.icon = 'sign-out';
+exports.input = true;
+exports.output = 1;
+exports.author = 'Martin Smola';
+exports.options = {};
+
+exports.html = `
+
@(Brokers)
+
Topic
+
@(Supports variables, example: \`device/{device-id}\`)
+
Static message(string)
+
@(Supports variables), @(If specified then incoming data are ignored and this message is sent instead. Topic is required if static message is defined.)
+
@(QoS)
+
@(Retain)
+
+`;
+
+exports.readme = `# MQTT publish
+
+If the topic field is left empty and the data object does not have a 'topic' property then nothing is send.
+Also if data object has a valid topic property it is assumed the object also have data property which is send as a payload;
+Example:
+\`\`\`javacsript
+{
+ topic: '/topic',
+ data: {
+ hello: 'world'
+ }
+}
+// in above case only { hello: 'world' } is published
+\`\`\`
+
+If the topic field is not empty then the entire incomming data object is passed to the output.`;
+
+
+exports.install = function(instance) {
+
+ var PUBLISH_OPTIONS = {};
+
+ var ready = false;
+
+ instance.custom.reconfigure = function() {
+
+ ready = false;
+
+ if (!MQTT.broker(instance.options.broker))
+ return instance.status('No broker', 'red');
+
+ if (instance.options.broker) {
+
+ MQTT.add(instance.options.broker, instance.id);
+ ready = true;
+ PUBLISH_OPTIONS.retain = instance.options.retain || false;
+ PUBLISH_OPTIONS.qos = parseInt(instance.options.qos || 0);
+ return;
+ }
+
+ instance.status('Not configured', 'red');
+ };
+
+ instance.on('options', instance.custom.reconfigure);
+
+ instance.on('data', function(flowdata) {
+ if (!ready)
+ return;
+ var msg = instance.options.staticmessage ? instance.arg(instance.options.staticmessage) : flowdata.data;
+ var topic = instance.arg(instance.options.topic || msg.topic);
+ if (topic) {
+ if (msg.topic)
+ msg = msg.data;
+ MQTT.publish(instance.options.broker, topic, msg, PUBLISH_OPTIONS);
+ } else
+ instance.debug('MQTT publish no topic');
+
+ instance.send(flowdata);
+ });
+
+ instance.on('close', function() {
+ MQTT.remove(instance.options.broker, instance.id);
+ OFF('mqtt.brokers.status', instance.custom.brokerstatus);
+ });
+
+
+ instance.custom.brokerstatus = function(status, brokerid, msg) {
+ if (brokerid !== instance.options.broker)
+ return;
+
+ switch (status) {
+ case 'connecting':
+ instance.status('Connecting', '#a6c3ff');
+ break;
+ case 'connected':
+ instance.status('Connected', 'green');
+ break;
+ case 'disconnected':
+ instance.status('Disconnected', 'red');
+ break;
+ case 'connectionfailed':
+ instance.status('Connection failed', 'red');
+ break;
+ case 'new':
+ !ready && instance.custom.reconfigure();
+ break;
+ case 'removed':
+ instance.custom.reconfigure();
+ break;
+ case 'error':
+ instance.status(msg, 'red');
+ break;
+ case 'reconfigured':
+ instance.options.broker = msg;
+ instance.reconfig();
+ instance.custom.reconfigure();
+ break;
+ }
+ }
+
+ ON('mqtt.brokers.status', instance.custom.brokerstatus);
+
+ instance.custom.reconfigure();
+};
diff --git a/flow/mqttsubscribe.js b/flow/mqttsubscribe.js
new file mode 100644
index 0000000..e866178
--- /dev/null
+++ b/flow/mqttsubscribe.js
@@ -0,0 +1,168 @@
+exports.id = 'mqttsubscribe';
+exports.title = 'MQTT subscribe';
+exports.group = 'MQTT';
+exports.color = '#888600';
+exports.version = '1.1.0';
+exports.icon = 'sign-in';
+exports.output = 1;
+exports.variables = true;
+exports.author = 'Martin Smola';
+exports.options = {};
+
+exports.html = `
+
@(Select a broker)
+
Topic
+
@(Supports variables, example: \`device/{device-id}\`)
+
@(QoS)
+
+`;
+
+exports.readme = `
+# MQTT subscribe
+
+The data recieved are passed to the output as follows:
+\`\`\`javascript
+{
+ topic: '/lights/on',
+ data: 'kitchen'
+}
+\`\`\`
+
+If the topic is wildcard then there's an array of matches in flowdata repository which can be used in Function component like so:
+\`\`\`javascript
+// wildcard -> /+/status
+// topic -> /devicename/status
+
+var match = flowdata.get('mqtt_wildcard');
+// match === ['devicename']
+\`\`\`
+
+More on wildcard topics [here](https://mosquitto.org/man/mqtt-7.html)
+`;
+
+exports.install = function(instance) {
+
+ var old_topic;
+ var ready = false;
+
+ instance.custom.reconfigure = function(o, old_options) {
+
+
+ ready = false;
+
+ if (!MQTT.broker(instance.options.broker))
+ return instance.status('No broker', 'red');
+
+ if (instance.options.broker && instance.options.topic) {
+
+ if (old_topic)
+ MQTT.unsubscribe(instance.options.broker, instance.id, old_topic);
+
+ old_topic = instance.arg(instance.options.topic);
+ MQTT.subscribe(instance.options.broker, instance.id, old_topic);
+ ready = true;
+ return;
+ }
+
+ instance.status('Not configured', 'red');
+ };
+
+ instance.on('options', instance.custom.reconfigure);
+
+ instance.on('close', function() {
+ MQTT.unsubscribe(instance.options.broker, instance.id, instance.options.topic);
+ OFF('mqtt.brokers.message', instance.custom.message);
+ OFF('mqtt.brokers.status', instance.custom.brokerstatus);
+ });
+
+ instance.custom.brokerstatus = function(status, brokerid, msg) {
+ if (brokerid !== instance.options.broker)
+ return;
+
+ switch (status) {
+ case 'connecting':
+ instance.status('Connecting', '#a6c3ff');
+ break;
+ case 'connected':
+ instance.status('Connected', 'green');
+ break;
+ case 'disconnected':
+ instance.status('Disconnected', 'red');
+ break;
+ case 'connectionfailed':
+ instance.status('Connection failed', 'red');
+ break;
+ case 'new':
+ !ready && instance.custom.reconfigure();
+ break;
+ case 'removed':
+ instance.custom.reconfigure();
+ break;
+ case 'error':
+ instance.status(msg, 'red');
+ break;
+ case 'reconfigured':
+ instance.options.broker = msg;
+ instance.reconfig();
+ instance.custom.reconfigure();
+ break;
+ }
+ }
+
+ instance.custom.message = function(brokerid, topic, message) {
+ if (brokerid !== instance.options.broker)
+ return;
+
+ var match = mqttWildcard(topic, old_topic);
+ if (match) {
+ var flowdata = instance.make({ topic: topic, data: message })
+ flowdata.set('mqtt_wildcard', match);
+ instance.send2(flowdata);
+ }
+ }
+
+ ON('mqtt.brokers.message', instance.custom.message);
+ ON('mqtt.brokers.status', instance.custom.brokerstatus);
+
+ instance.custom.reconfigure();
+};
+
+// https://github.com/hobbyquaker/mqtt-wildcard
+function mqttWildcard(topic, wildcard) {
+ if (topic === wildcard) {
+ return [];
+ } else if (wildcard === '#') {
+ return [topic];
+ }
+
+ var res = [];
+
+ var t = String(topic).split('/');
+ var w = String(wildcard).split('/');
+
+ var i = 0;
+ for (var lt = t.length; i < lt; i++) {
+ if (w[i] === '+') {
+ res.push(t[i]);
+ } else if (w[i] === '#') {
+ res.push(t.slice(i).join('/'));
+ return res;
+ } else if (w[i] !== t[i]) {
+ return null;
+ }
+ }
+
+ if (w[i] === '#') {
+ i += 1;
+ }
+
+ return (i === w.length) ? res : null;
+}
diff --git a/flow/nodesdb_changecheck.js b/flow/nodesdb_changecheck.js
new file mode 100644
index 0000000..be1e700
--- /dev/null
+++ b/flow/nodesdb_changecheck.js
@@ -0,0 +1,70 @@
+exports.id = 'nodesdb_change_check';
+exports.title = 'Nodes DB change check';
+exports.group = 'Worksys';
+exports.color = '#888600';
+exports.version = '1.0.2';
+exports.icon = 'sign-out';
+exports.input = 1;
+exports.output = 1;
+exports.readme = `Check, if nodes.table db changed compared to original database`;
+
+const fs = require('fs');
+const path = require('path');
+const { sendNotification } = require('./helper/notification_reporter');
+const nodesOriginalFile = path.join(__dirname, '../databases/nodes_original/', 'nodes_original.table');
+
+
+exports.install = function(instance) {
+
+ function compareArrays(array1, array2) {
+ let message = "";
+ let areEqual = true;
+ let zmenene = []
+
+ if (array1.length !== array2.length) {
+ message += "Nezhoda v pocte nodov. "
+ }
+
+ const set1 = new Set(array1.map(obj => JSON.stringify(obj)));
+ const set2 = new Set(array2.map(obj => JSON.stringify(obj)));
+
+ for (const objStr of set1) {
+
+ if (!set2.has(objStr)) {
+ zmenene.push(objStr)
+ areEqual = false;
+ } else {
+ set2.delete(objStr);
+ }
+ }
+
+ if(!areEqual) {
+ message += `Aktualne nody: ${zmenene.toString()}. Zmenene proti originalu: ${Array.from(set2).join(' ')}`;
+ sendNotification("Nodesdb_changecheck", FLOW.GLOBALS.settings.rvoTbName, "nodes_db_changed", "", message, 0, instance);
+ }
+ else console.log("Arrays are equal.");
+
+ console.log(message)
+ }
+
+
+ instance.on("data", _ => {
+
+ let nodesData = FLOW.GLOBALS.nodesData;
+
+ // we check if nodes.table has changed compared to nodes_original.table (we have array of nodes e.g. [{node:255, tbname: "agruhuwhgursuhgo34hgsdiguhrr"}]
+ const nodes_actual = Object.keys(nodesData).map(node => ({[node]: nodesData[node].tbname}))
+ let nodes_original = fs.readFileSync(nodesOriginalFile, { encoding: 'utf8', flag: 'r' });
+
+ try {
+ nodes_original = JSON.parse(nodes_original);
+ } catch(e) {
+ console.log(e)
+ }
+
+
+ setTimeout(() => compareArrays(nodes_actual, nodes_original),10000);
+ })
+
+}
+
diff --git a/flow/nosql.js b/flow/nosql.js
new file mode 100644
index 0000000..db6b7c4
--- /dev/null
+++ b/flow/nosql.js
@@ -0,0 +1,191 @@
+exports.id = 'nosql';
+exports.title = 'NoSQL';
+exports.version = '1.2.1';
+exports.group = 'Databases';
+exports.author = 'Martin Smola';
+exports.color = '#D770AD';
+exports.icon = 'database';
+exports.input = true;
+exports.output = 2;
+exports.options = {};
+exports.readme = `# NoSQL embedded
+
+## Outputs
+
+First output is response from nosql engine and second is the data passed in.
+
+## Collection
+
+if the collection field is left empty, then we try to look at \`flowdata.get('collection')\`, to set this value you need to use \`flowdata.set('collection', '
')\` in previous component (currently only \`function\` can be used)
+
+## Insert
+
+- will insert recieved data
+- expects data to be an Object
+- returns error, success, id
+
+## Read
+
+- will read a document by id
+- expects data to be an Object with an \`id\` property
+- returns error, response
+
+## Update
+
+- will update document by id
+- expects data to be an Object with \`id\` property and all the props to be updated
+- returns error, response
+- if response is 0 then update failed
+
+## Remove
+
+- will remove document by id
+- expects data to be an Object with an \`id\` property
+- returns error, response
+- if response is 0 then remove failed
+
+## Query
+
+- will query DB
+- expects data to be an Array as shown bellow
+- returns error, response
+
+\`\`\`javascript
+[
+ ['where', 'sensor', 'temp'], // builder.where('sensor', 'temp');
+ ['limit', 2] // builder.limit(2);
+]
+\`\`\``;
+
+exports.html = `
+
+
DB collection name
+
@(Method)
+
+
Add unique ID to data before insert
+
+
+
Insert document if it doesn't exist
+
Add unique ID to data before insert (only if it doesn't exist)
+
+
`;
+
+exports.install = function(instance) {
+
+ instance.on('data', function(flowdata, next) {
+
+ instance.send2(1, flowdata.clone());
+
+ var options = instance.options;
+ var collection = options.collection || flowdata.get('collection');
+ if (!collection) {
+ flowdata.data = { err: '[DB] No collection specified' };
+ next(0, flowdata);
+ instance.error('[DB] No collection specified');
+ return;
+ }
+
+ var nosql = NOSQL(collection);
+ var builder;
+
+ if (options.method === 'read') {
+
+ if (!flowdata.data.id) {
+ flowdata.data = { err: '[DB] Cannot get record by id: `undefined`' };
+ next(0, flowdata);
+ instance.error('[DB] Cannot get record by id: `undefined`');
+ return;
+ }
+
+ builder = nosql.find();
+ builder.where('id', flowdata.data.id);
+ builder.first();
+ builder.callback(function(err, response) {
+ if (err) {
+ instance.throw(err);
+ } else {
+ flowdata.data = { response: response };
+ next(0, flowdata);
+ }
+ });
+
+ } else if (options.method === 'insert') {
+
+ options.addid && (flowdata.data.id = UID());
+ nosql.insert(flowdata.data).callback(function(err) {
+ if (err)
+ instance.throw(err);
+ else {
+ flowdata.data = { success: err ? false : true, id: flowdata.data.id };
+ next(0, flowdata);
+ }
+ });
+
+ } else if (options.method === 'query') {
+
+ var query = flowdata.data;
+ builder = nosql.find();
+
+ query && query instanceof Array && query.forEach(function(q) {
+ if (q instanceof Array) {
+ var m = q[0];
+ var args = q.splice(1);
+ builder[m] && (builder[m].apply(builder, args));
+ }
+ });
+
+ builder.callback(function(err, response) {
+ if (err) {
+ instance.throw(err);
+ } else {
+ flowdata.data = { response: response || [] };
+ next(0, flowdata);
+ }
+ });
+
+ } else if (options.method === 'update') {
+
+ if (!options.upsert && !flowdata.data.id) {
+ flowdata.data = { err: '[DB] Cannot update record by id: `undefined`' };
+ next(0, flowdata);
+ instance.error('[DB] Cannot update record by id: `undefined`');
+ return;
+ }
+
+ if (options.upsert && (options.upsertid && !flowdata.data.id)) {
+ flowdata.data.id = UID();
+ builder = nosql.modify(flowdata.data, options.upsert);
+ builder.where('id', flowdata.data.id);
+ builder.callback(function(err, count) {
+ if (err)
+ instance.throw(err);
+ else {
+ flowdata.data = { response: count || 0 };
+ next(0, flowdata);
+ }
+ });
+ }
+
+ } else if (options.method === 'remove') {
+
+ if (!flowdata.data.id) {
+ flowdata.data = { err: '[DB] Cannot remove record by id: `undefined`' };
+ next(0, flowdata);
+ instance.error('[DB] Cannot remove record by id: `undefined`');
+ return;
+ }
+
+ builder = nosql.remove();
+ builder.where('id', flowdata.data.id);
+ builder.callback(function(err, count) {
+ if (err)
+ instance.throw(err);
+ else {
+ flowdata.data = { response: count || 0 };
+ next(0, flowdata);
+ }
+ });
+ }
+
+ });
+};
diff --git a/flow/notifikacie.csv b/flow/notifikacie.csv
deleted file mode 100644
index 520c997..0000000
--- a/flow/notifikacie.csv
+++ /dev/null
@@ -1,31 +0,0 @@
-key;weight;en;sk
-switching_profile_point_applied_to_line;INFO;Switching profile point applied to line no. ${line} : ${value};Aplikovaný bod spínacieho profilu na línií č. ${line} : ${value}
-dusk_has_occured;INFO;Dusk has occured;Nastal súmrak
-dawn_has_occured;INFO;Dawn has occured;Nastal úsvit
-dimming_profile_was_successfully_received_by_node;NOTICE;Dimming profile was successfully received by node no. ${node};Stmievací profil bol úspešne prijatý nodom č. ${node}
-master_node_is_responding_again;NOTICE;Master node is responding again;Master node začal znovu odpovedať
-command_was_sent_from_terminal_interface;DEBUG;A command was sent from terminal interface;Z terminálu bol odoslaný príkaz
-master_node_is_not_responding;ALERT;Master node is not responding;Master node neodpovedá
-configuration_of_dimming_profile_to_node_failed;ALERT;Configuration of dimming profile to node no. ${node} has failed;Konfigurácia stmievacieho profilu pre node č. ${node} zlyhala
-circuit_breaker_was_turned_on_line;NOTICE;Circuit breaker was turned on - line no. ${line};Zapnutie ističa na línii č. ${line}
-circuit_breaker_was_turned_off_line;ERROR;Circuit breaker was turned off - line no. ${line};Vypnutie ističa na línií č. ${line}
-dimming_profile_was_processed_for_node;INFO;Dimming profile was processed for node no. ${node};Stmievací profil bol spracovaný pre node č. ${node}
-switching_profile_was_processed_for_line;INFO;Switching profile was processed for line no. ${line};Spínací profil bol spracovaný pre líniu č. ${line}
-thermometer_is_not_responding;WARNING;Thermometer is not responding;Teplomer neodpovedá
-thermometer_is_responding_again;NOTICE;Thermometer is responding again;Teplomer znovu odpovedá
-thermometer_sends_invalid_data;WARNING;Thermometer sends invalid data;Teplomer posiela neplatné hodnoty
-main_switch_has_been_turned_off;CRITICAL;Main switch has been turned off;Hlavný vypínač bol vypnutý
-main_switch_has_been_turned_on;NOTICE;Main switch has been turned on;Hlavný vypínač bol zapnutý
-power_supply_has_disconnected_input;ALERT;Power supply has disconnected input;Napájací zdroj nemá napätie na vstupe
-power_supply_works_correctly;NOTICE;Power supply works correctly ;Napájací zdroj pracuje správne
-battery_level_is_low;ERROR;Battery level is low;Batéria má nízku úroveň napätia
-battery_level_is_ok;NOTICE;Battery level is OK;Batéria má správnu úroveň napätia
-door_has_been_open;NOTICE;Door has been open;Dvere boli otvorené
-door_has_been_closed;NOTICE;Door has been closed;Dvere boli zatvorené
-door_has_been_open_without_permision_alarm_is_on;WARNING;Door has been open without permision - alarm is on;Dvere boli otvorené bez povolania - zapnutá siréna
-state_of_contactor_for_line;INFO;State of contactor for line no. ${line} is ${value};Stav stýkača pre líniu č. ${line} je ${value}
-local_database_is_corrupted;CRITICAL;;
-electrometer_is_not_responding;ERROR;Electrometer is not responding;Elektromer neodpovedá
-no_voltage_detected_on_phase;CRITICAL;No voltage detected on phase no. ${phase};Na fáze č. ${phase} nie je napätie
-electrometer_is_responding_again;NOTICE;Electrometer is responding again;Elektromer znovu odpovedá
-voltaga_on_phase_has_been_restored;NOTICE;Voltaga on phase no. ${phase} has been restored;Napätie na fáze č. ${phase} bolo obnovené
diff --git a/flow/operations_error.csv b/flow/operations_error.csv
new file mode 100644
index 0000000..484ea07
--- /dev/null
+++ b/flow/operations_error.csv
@@ -0,0 +1,595 @@
+Production line;Operation;Error type;Error code;Orig Message (EN);User defined error
+CMFB;OP10;C_STOP;121;Machine Not At Home Position;
+CMFB;OP10;C_STOP;122;Auto Mode Not Selected;
+CMFB;OP10;C_STOP;125;Part NOK;
+CMFB;OP10;C_STOP;140;Left Shift Conduit Contact Detect Sensor Backcheck Error;
+CMFB;OP10;C_STOP;141;Left Select Conduit Contact Detect Sensor Backcheck Error;
+CMFB;OP10;C_STOP;142;Right Shift Conduit Contact Detect Sensor Backcheck Error;
+CMFB;OP10;C_STOP;143;Right Select Conduit Contact Detect Sensor Backcheck Error;
+CMFB;OP10;C_STOP;144;Left Shift Conduit In Place Sensor Backcheck Error;
+CMFB;OP10;C_STOP;145;Left Select Conduit In Place Sensor Backcheck Error;
+CMFB;OP10;C_STOP;146;Right Select Conduit In Place Sensor Backcheck Error;
+CMFB;OP10;C_STOP;147;Left Shift Conduit In Place Sensor Backcheck Error;
+CMFB;OP10;C_STOP;148;Left_Shift_Conduit_Placed_In_Place Sensors Backcheck Error;
+CMFB;OP10;C_STOP;149;Left_Select_Conduit_Placed_In_Place Sensors Backcheck Error;
+CMFB;OP10;C_STOP;150;Right_Shift_Conduit_Placed_In_Place Sensors Backcheck Error;
+CMFB;OP10;C_STOP;151;Right_Select_Conduit_Placed_In_Place Sensors Backcheck Error;
+CMFB;OP10;I_STOP;101;Left Clampping Conduit Cylinder Home Position Timeout Error [I3.1&I3.3,Q3.3],;
+CMFB;OP10;I_STOP;102;Left Clampping Conduit Cylinder Work Position Timeout Error [I3.0&I3.2,Q3.2],;
+CMFB;OP10;I_STOP;103;Left Clampping Conduit Cylinder Sensors Miscompare [I3.1&I3.3,I3.0&I3.2],;
+CMFB;OP10;I_STOP;104;Right Clampping Conduit Cylinder Work Position Timeout Error [I4.0&I4.2,Q3.4],;
+CMFB;OP10;I_STOP;105;Right Clampping Conduit Cylinder Home Position Timeout Error [I4.1&I4.3,Q3.5],;
+CMFB;OP10;I_STOP;106;Right Clampping Conduit Cylinder Sensors Miscompare [I4.1&I4.3,I4.0&I4.2],;
+CMFB;OP10;I_STOP;107;Right Clipping Conduit Cylinder Work Position Timeout Error [I5.2,Q3.6],;
+CMFB;OP10;I_STOP;108;Right Clipping Conduit Cylinder Home Position Timeout Error [I5.3,Q3.7],;
+CMFB;OP10;I_STOP;109;Right Clipping Cylinder Sensors Miscompare [I3.1&I3.3,I3.0&I3.2],;
+CMFB;OP10;I_STOP;110;Left Clipping Cylinder Work Position Timeout Error [I6.2,Q5.2],;
+CMFB;OP10;I_STOP;111;Left Clipping Cylinder Home Position Timeout Error [I6.3,Q5.3],;
+CMFB;OP10;I_STOP;112;Left Clipping Cylinder Sensors Miscompare [I6.2,I6.3],;
+CMFB;OP10;I_STOP;113;Right Striping Cylinder Work Position Timeout Error [I5.0,Q4.0],;
+CMFB;OP10;I_STOP;114;Right Striping Cylinder Home Position Timeout Error [I3.1&I3.3,Q3.3],;
+CMFB;OP10;I_STOP;115;Right Striping Cylinder Sensors Miscompare [I3.1&I3.3,I3.0&I3.2],;
+CMFB;OP10;I_STOP;116;Left Striping Cylinder Work Position Timeout Error [I6.0,Q5.4],;
+CMFB;OP10;I_STOP;117;Left Stripping Cylinder Work Position Timeout Error [I6.1,Q5.5],;
+CMFB;OP10;I_STOP;118;Left Stripping Cylinder Sensors Miscompare [I6.0,I6.1],;
+CMFB;OP10;I_STOP;119;Left Escaping Cylinder Work Position Timeout Error [I6.4,Q5.6],;
+CMFB;OP10;I_STOP;120;Left Escaping Cylinder Home Position Timeout Error [I6.5,Q5.7],;
+CMFB;OP10;I_STOP;121;Left Escaping Cylinder Sensors Miscompare [I6.4,I6.5],;
+CMFB;OP10;I_STOP;122;Right Escaping Cylinder Work Position Timeout Error [I5.4,Q4.2],;
+CMFB;OP10;I_STOP;123;Right Escaping Cylinder Home Position Timeout Error [I5.5,Q4.3],;
+CMFB;OP10;I_STOP;124;Right Escaping Cylinder Sensors Miscompare [I5.4,I5.5],;
+CMFB;OP10;I_STOP;125;UP Clamping End of Conduit Cylinder Work Position Timeout Error [I8.0&I8.4,Q4.7],;
+CMFB;OP10;I_STOP;126;UP Clamping End of Conduit Cylinder Home Position Timeout Error [I8.1&I8.5,Q4.6],;
+CMFB;OP10;I_STOP;127;UP Clamping End of Conduit Cylinder Sensors Miscompare [I8.0&I8.4,I8.1&I8.5],;
+CMFB;OP10;I_STOP;128;DOWN Clamping End of Conduit Cylinder Work Position Timeout Error [I8.2&I8.6,Q4.4],;
+CMFB;OP10;I_STOP;129;DOWN Clamping End of Conduit Cylinder Home Position Timeout Error [I8.3&I8.7,Q4.5],;
+CMFB;OP10;I_STOP;130;DOWN Clamping End of Conduit Cylinder Sensors Miscompare [I8.2&I8.6,I8.3&I8.7],;
+CMFB;OP10;I_STOP;131;Fixture Moving Cylinder Work Position Timeout Error [I7.0,Q5.0],;
+CMFB;OP10;I_STOP;132;Fixture Moving Cylinder Home Position Timeout Error [I7.1,Q5.1],;
+CMFB;OP10;I_STOP;133;Fixture Moving Cylinder Sensors Miscompare Error[I7.0,I7.1],;
+CMFB;OP10;I_STOP;134;Hydraulic Cylinder Work Positio Timeout Error,;
+CMFB;OP10;I_STOP;135;Hydraulic Cylinder Home Position Timeout Error[I7.2],;
+CMFB;OP10;I_STOP;136;Hydraulic Cylinder Sensors Miscompare Error,;
+CMFB;OP10;I_STOP;137;Left Press Conduit Cylinder Work Positio Timeout Error[I10.3],;
+CMFB;OP10;I_STOP;138;Left Press Conduit Cylinder Home Positio Timeout Error[I10.2],;
+CMFB;OP10;I_STOP;139;Left Press Conduit Cylinder Sensors Miscompare Error[I10.2,I10.3],;
+CMFB;OP10;I_STOP;140;Right Press Conduit Cylinder Work Positio Timeout Error[I10.5],;
+CMFB;OP10;I_STOP;141;Right Press Conduit Cylinder Home Positio Timeout Error[I10.4],;
+CMFB;OP10;I_STOP;142;Right Press Conduit Cylinder Sensors Miscompare Error[I10.4,I10.5],;
+CMFB;OP10;I_STOP;151;Emergency Stop Relay Not ON,Pls Press Reset Button.,;
+CMFB;OP10;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP20A;C_STOP;101;Light Curtain Blocked(I2.0),;
+CMFB;OP20A;C_STOP;121;Machine Not At Home Position,;
+CMFB;OP20A;C_STOP;122;Auto Mode Not Selected,;
+CMFB;OP20A;C_STOP;125;The Part Is NOK,;
+CMFB;OP20A;C_STOP;140;Grommet Assembly_PositionLeft sensor backcheck fault[I8.0],;
+CMFB;OP20A;C_STOP;141;Grommet Assembly_PositionRight sensor backcheck fault[I8.1],;
+CMFB;OP20A;C_STOP;142;AssemblyOK_Left_Front sensor backcheck fault[I8.2],;
+CMFB;OP20A;C_STOP;143;AssemblyOK_Left_Back sensor backcheck fault[I8.3],;
+CMFB;OP20A;C_STOP;144;AssemblyOK_Right_Front sensor backcheck fault[I8.4],;
+CMFB;OP20A;C_STOP;145;AssemblyOK_Right_Back sensor backcheck fault[I8.5],;
+CMFB;OP20A;C_STOP;146;Grommet present sensor backcheck fault[I5.6],;
+CMFB;OP20A;C_STOP;147;Clip check_front sensor backcheck fault[I9.6],;
+CMFB;OP20A;C_STOP;148;Clip check_back sensor backcheck fault[9.7],;
+CMFB;OP20A;C_STOP;149;Gromment left sensor backcheck fault[I8.6],;
+CMFB;OP20A;C_STOP;150;Check Sensor 11 Backcheck Error,;
+CMFB;OP20A;C_STOP;151;Check Sensor 12 Backcheck Error,;
+CMFB;OP20A;C_STOP;152;Check Sensor 13 Backcheck Error;
+CMFB;OP20A;I_STOP;100;Pressing cylinder Sensor Miscompare[I4.4,I4.5],;
+CMFB;OP20A;I_STOP;101;Clip ClampCylinder_front Work Position Timeout Errror[I9.1],;
+CMFB;OP20A;I_STOP;102;Clip ClampCylinder_front Home Position Timeout Errror[I9.0],;
+CMFB;OP20A;I_STOP;103;Clip ClampCylinder_front Sensor Miscompare[I9.0,I9.1],;
+CMFB;OP20A;I_STOP;104;Clip ClampCylinder_back Work Position Timeout Errror[I9.3],;
+CMFB;OP20A;I_STOP;105;Clip ClampCylinder_back Home Position Timeout Errror[I9.2],;
+CMFB;OP20A;I_STOP;106;Clip ClampCylinder_back Sensor Miscompare[I9.2,I9.3],;
+CMFB;OP20A;I_STOP;107;Clip Assembly Cylinder Work Position Timeout Errror[I9.5],;
+CMFB;OP20A;I_STOP;116;Clip Assembly Cylinder Home Position Timeout Errror[I9.4],;
+CMFB;OP20A;I_STOP;117;Clip Assembly Cylinder Sensor Miscompare[I9.4,I9.5],;
+CMFB;OP20A;I_STOP;151;Emergency Stop Relay Not ON,;
+CMFB;OP20A;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP20B;C_STOP;100;Load Material cylinder Work Position Timeout Errror[I4.1],;
+CMFB;OP20B;C_STOP;101;Load Material cylinder Home Position Timeout Errror[I4.0],;
+CMFB;OP20B;C_STOP;102;Load Material cylinder Sensor Miscompare[I4.0,I4.1],;
+CMFB;OP20B;C_STOP;103;The Assembly of cylinder Work Position Timeout Errror[I4.3],;
+CMFB;OP20B;C_STOP;104;The Assembly of cylinder Home Position Timeout Errror[I4.2],;
+CMFB;OP20B;C_STOP;105;The Assembly of cylinder Sensor Miscompare[I4.2,I4.3],;
+CMFB;OP20B;C_STOP;106;Pressing cylinder Work Position Timeout Errror[I4.5],;
+CMFB;OP20B;C_STOP;107;Pressing cylinder Home Position Timeout Errror[I4.4],;
+CMFB;OP20B;C_STOP;108;Pressing cylinder Sensor Miscompare[I4.4,I4.5],;
+CMFB;OP20B;C_STOP;109;Clip ClampCylinder_front Work Position Timeout Errror[I9.1],;
+CMFB;OP20B;C_STOP;110;Clip ClampCylinder_front Home Position Timeout Errror[I9.0],;
+CMFB;OP20B;C_STOP;111;Clip ClampCylinder_front Sensor Miscompare[I9.0,I9.1],;
+CMFB;OP20B;C_STOP;112;Clip ClampCylinder_back Work Position Timeout Errror[I9.3],;
+CMFB;OP20B;C_STOP;113;Clip ClampCylinder_back Home Position Timeout Errror[I9.2],;
+CMFB;OP20B;C_STOP;114;Clip ClampCylinder_back Sensor Miscompare[I9.2,I9.3],;
+CMFB;OP20B;C_STOP;115;Clip Assembly Cylinder Work Position Timeout Errror[I9.5],;
+CMFB;OP20B;C_STOP;126;Clip Assembly NOK!,;
+CMFB;OP20B;C_STOP;140;Select Damper Prestretching sensor backcheck fault[I5.0],;
+CMFB;OP20B;C_STOP;141;Select Omgea Prestretching sensor backcheck fault[I5.1],;
+CMFB;OP20B;C_STOP;142;Shift Damper Prestretching sensor backcheck fault[I5.2],;
+CMFB;OP20B;C_STOP;143;Shift Omgea Prestretching sensor backcheck fault[I5.3],;
+CMFB;OP20B;C_STOP;144;Gromment ASSY Postion1 sensor backcheck fault[I5.4],;
+CMFB;OP20B;C_STOP;145;Gromment ASSY Postion2 sensor backcheck fault[I5.5],;
+CMFB;OP20B;C_STOP;146;Grommet present_Right sensor backcheck fault[I5.6];
+CMFB;OP20B;I_STOP;100;Rotating Pressure cylinder Sensor Miscompare[I7.2,I7.3],;
+CMFB;OP20B;I_STOP;101;Cover Cylinder Work Position Timeout Errror[I7.1],;
+CMFB;OP20B;I_STOP;102;Cover Cylinder Home Position Timeout Errror[I7.0],;
+CMFB;OP20B;I_STOP;103;Cover Cylinder Sensor Miscompare[I7.0,I7.1],;
+CMFB;OP20B;I_STOP;108;Remodel cylinder Work Position Timeout Errror[I7.7],;
+CMFB;OP20B;I_STOP;109;Remodel cylinder Home Position Timeout Errror[I7.6],;
+CMFB;OP20B;I_STOP;110;Remodel cylinder Sensor Miscompare[I7.6,I7.7],;
+CMFB;OP20B;I_STOP;111;Limit cylinder Work Position Timeout Errror[I7.5],;
+CMFB;OP20B;I_STOP;112;Limit cylinder Home Position Timeout Errror[I7.4],;
+CMFB;OP20B;I_STOP;113;Limit cylinder Sensor Miscompare[I7.4,I7.5],;
+CMFB;OP20B;I_STOP;114;Rotating Pressure cylinder Work Position Timeout Errror[I7.3],;
+CMFB;OP20B;I_STOP;115;Rotating Pressure cylinder Home Position Timeout Errror[I7.2];
+CMFB;OP30A;C_STOP;101; Left Station Light Curtain Blocked(I2.0),;
+CMFB;OP30A;C_STOP;121; Machine Not At Home Position_L,;
+CMFB;OP30A;C_STOP;122; Auto Mode Not Selected_L,;
+CMFB;OP30A;C_STOP;125; The Part Of Station Is NOK,;
+CMFB;OP30A;C_STOP;140; left front select swivetube present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;141; left front select swivetube assy present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;142; left front select omgea present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;143; left inside select swivetube present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;144; left inside select swivetube assy present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;145; left inside select omgea present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;146; right outside shift omgea present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;147; right outside shift swiveltube assy present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;148; right outside shift swiveltube present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;149; right inside shift omgea present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;150; right inside shift swiveltube assy present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;151; right inside shift swiveltube present sensor backcheck fault,;
+CMFB;OP30A;C_STOP;152; romemet assy present sensor backcheck fault;
+CMFB;OP30A;I_STOP;100;left front select rotating cylinder Work Position Timeout Errror[I3.1],;
+CMFB;OP30A;I_STOP;101;left front select rotating cylinder Home Position Timeout Errror[I3.0],;
+CMFB;OP30A;I_STOP;102;left front select rotating cylinder Sensor Miscompare[I3.0,I3.1],;
+CMFB;OP30A;I_STOP;103;left front select pull in cylinder Work Position Timeout Errror[I3.3],;
+CMFB;OP30A;I_STOP;104;left front select pull in cylinder Home Position Timeout Errror[I3.2],;
+CMFB;OP30A;I_STOP;105;left front select pull in cylinder Sensor Miscompare[I3.2,I3.3],;
+CMFB;OP30A;I_STOP;106;outside select prepull testing force not reach 1000N,;
+CMFB;OP30A;I_STOP;107;outside select prepull testing cylinder Home Position Timeout Errror[I3.4],;
+CMFB;OP30A;I_STOP;108;outside select prepull testing cylinder Sensor Miscompare[I3.4,I3.5],;
+CMFB;OP30A;I_STOP;109;left outside lifting release cylinder Work Position Timeout Errror[I3.7],;
+CMFB;OP30A;I_STOP;110;left outside lifting release cylinder Home Position Timeout Errror[I3.6],;
+CMFB;OP30A;I_STOP;111;left outside lifting release cylinder Cylinder Sensor Miscompare[I3.6,I3.7],;
+CMFB;OP30A;I_STOP;112;left outside select griping cylinder Work Position Timeout Errror[I4.1],;
+CMFB;OP30A;I_STOP;113;left outside select griping cylinder Home Position Timeout Errror[I4.0],;
+CMFB;OP30A;I_STOP;114;left outside select griping cylinder Sensor Miscompare[I4.0,I4.1],;
+CMFB;OP30A;I_STOP;115;outside pullout testing cylinder Work Position Timeout Errror[I4.3],;
+CMFB;OP30A;I_STOP;116;outside pullout testing cylinder Home Position Timeout Errror[I4.2],;
+CMFB;OP30A;I_STOP;117;outside pullout testing cylinder Sensor Miscompare[I4.2,I4.3],;
+CMFB;OP30A;I_STOP;118;left inside shift rotating cylinder Work Position Timeout Errror[I5.1],;
+CMFB;OP30A;I_STOP;119;left inside shift rotating cylinder Home Position Timeout Errror[I5.0],;
+CMFB;OP30A;I_STOP;120;left inside shift rotating cylinder Sensor Miscompare[I5.0,I5.1],;
+CMFB;OP30A;I_STOP;121;left inside shift pull in cylinder Work Position Timeout Errror[I5.3],;
+CMFB;OP30A;I_STOP;122;left inside shift pull in cylinder Home Position Timeout Errror[I5.2],;
+CMFB;OP30A;I_STOP;123;left inside shift pull in cylinder Sensor Miscompare[I5.2,I5.3],;
+CMFB;OP30A;I_STOP;124;Inside select prepull testing force not reach 1000N,;
+CMFB;OP30A;I_STOP;125;Inside select prepull testing cylinder Home Position Timeout Errror[I5.4],;
+CMFB;OP30A;I_STOP;126;Inside select prepull testing cylinder Sensor Miscompare[I5.4,I5.5],;
+CMFB;OP30A;I_STOP;127;left inside lifting release cylinder Work Position Timeout Errror[I5.7],;
+CMFB;OP30A;I_STOP;128;left inside lifting release cylinder Home Position Timeout Errror[I5.6],;
+CMFB;OP30A;I_STOP;129;left inside lifting release cylinder Sensor Miscompare[I5.6,I5.7],;
+CMFB;OP30A;I_STOP;130;left inside shift griping cylinder Work Position Timeout Errror[I6.1],;
+CMFB;OP30A;I_STOP;131;left inside shift griping cylinder Home Position Timeout Errror[I6.0],;
+CMFB;OP30A;I_STOP;132;left inside shift griping cylinder Sensor Miscompare[I6.0,I6.1],;
+CMFB;OP30A;I_STOP;133;inside pullout testing cylinder Work Position Timeout Errror[I6.3],;
+CMFB;OP30A;I_STOP;134;inside pullout testing cylinder Home Position Timeout Errror[I6.2],;
+CMFB;OP30A;I_STOP;135;inside pullout testing cylinder Sensor Miscompare[I6.2,I6.3],;
+CMFB;OP30A;I_STOP;136;right outside select pull in cylinder Work Position Timeout Errror[I7.1],;
+CMFB;OP30A;I_STOP;137;right outside select pull in cylinder Home Position Timeout Errror[I7.0],;
+CMFB;OP30A;I_STOP;138;right outside select pull in cylinder Sensor Miscompare[I7.0,I7.1],;
+CMFB;OP30A;I_STOP;139;right outside lifting release cylinder Work Position Timeout Errror[I7.3],;
+CMFB;OP30A;I_STOP;140;right outside lifting release cylinder Home Position Timeout Errror[I7.2],;
+CMFB;OP30A;I_STOP;141;right outside lifting release cylinder Sensor Miscompare[I7.2,I7.3],;
+CMFB;OP30A;I_STOP;142;right outside select griping the cylinder Work Position Timeout Errror[I7.5],;
+CMFB;OP30A;I_STOP;143;right outside select griping the cylinder Home Position Timeout Errror[I7.4],;
+CMFB;OP30A;I_STOP;144;right outside select griping the cylinder Sensor Miscompare[I7.4,I7.5],;
+CMFB;OP30A;I_STOP;145;right outside select rotating cylinder Work Position Timeout Errror[I7.7],;
+CMFB;OP30A;I_STOP;146;right outside select rotating cylinder Home Position Timeout Errror[I7.6],;
+CMFB;OP30A;I_STOP;147;right outside select rotating cylinder Sensor Miscompare[I7.6,I7.7],;
+CMFB;OP30A;I_STOP;148;left outside positioning cylinder Work Position Timeout Errror[I8.1],;
+CMFB;OP30A;I_STOP;149;left outside positioning cylinder Home Position Timeout Errror[I8.0],;
+CMFB;OP30A;I_STOP;150;left outside positioning cylinder Sensor Miscompare[I8.0,I8.1],;
+CMFB;OP30A;I_STOP;151;right outside positioning cylinder Work Position Timeout Errror[I8.3],;
+CMFB;OP30A;I_STOP;152;right outside positioning cylinder Home Position Timeout Errror[I8.2],;
+CMFB;OP30A;I_STOP;153;right outside positioning cylinder Sensor Miscompare[I8.2,I8.3],;
+CMFB;OP30A;I_STOP;154;right inside select rotating cylinder Work Position Timeout Errror[I9.1],;
+CMFB;OP30A;I_STOP;155;right inside select rotating cylinder Home Position Timeout Errror[I9.0],;
+CMFB;OP30A;I_STOP;156;right inside shift rotating cylinder Sensor Miscompare[I9.0,I9.1],;
+CMFB;OP30A;I_STOP;157;right inside shift pull in cylinder Work Position Timeout Errror[I9.3],;
+CMFB;OP30A;I_STOP;158;right inside shift pull in cylinder Home Position Timeout Errror[I9.2],;
+CMFB;OP30A;I_STOP;159;right inside shift pull in cylinder Sensor Miscompare[I9.2,I9.3],;
+CMFB;OP30A;I_STOP;160;right inside lifting release cylinder Work Position Timeout Errror[I9.5],;
+CMFB;OP30A;I_STOP;161;right inside lifting release cylinder Home Position Timeout Errror[I9.4],;
+CMFB;OP30A;I_STOP;162;right inside lifting release cylinder Sensor Miscompare[I9.4,I9.5],;
+CMFB;OP30A;I_STOP;163;right inside shift griping the cylinder Work Position Timeout Errror[I9.7],;
+CMFB;OP30A;I_STOP;164;right inside shift griping the cylinder Home Position Timeout Errror[I9.6],;
+CMFB;OP30A;I_STOP;165;right inside shift griping the cylinder Sensor Miscompare[I9.6,I9.7],;
+CMFB;OP30A;I_STOP;166;left inside postiton cylinder Work Position Timeout Errror[I10.1],;
+CMFB;OP30A;I_STOP;167;left inside postiton cylinder Home Position Timeout Errror[I10.0],;
+CMFB;OP30A;I_STOP;168;left inside postiton cylinder Sensor Miscompare[I10.0,I10.1],;
+CMFB;OP30A;I_STOP;169;right inside positioning cylinder Work Position Timeout Errror[I10.3],;
+CMFB;OP30A;I_STOP;170;right inside positioning cylinder Home Position Timeout Errror[I10.2],;
+CMFB;OP30A;I_STOP;171;right inside positioning cylinder Sensor Miscompare[I10.2,I10.3];
+CMFB;OP30B;C_STOP;101;" Left Station Light Curtain Blocked(I2.0),";
+CMFB;OP30B;C_STOP;121;" Machine Not At Home Position_L,";
+CMFB;OP30B;C_STOP;122;" Auto Mode Not Selected_L,";
+CMFB;OP30B;C_STOP;125;" The Part Of Station Is NOK,";
+CMFB;OP30B;C_STOP;140;" left front select swivetube present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;141;" left front select swivetube assy present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;142;" left front select omgea present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;143;" left inside select swivetube present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;144;" left inside select swivetube assy present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;145;" left inside select omgea present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;146;" right outside shift omgea present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;147;" right outside shift swiveltube assy present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;148;" right outside shift swiveltube present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;149;" right inside shift omgea present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;150;" right inside shift swiveltube assy present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;151;" right inside shift swiveltube present sensor backcheck fault,";
+CMFB;OP30B;C_STOP;152;" romemet assy present sensor backcheck fault";
+CMFB;OP30B;I_STOP;100;" left front select rotating cylinder Work Position Timeout Errror[I3.1],";
+CMFB;OP30B;I_STOP;101;" left front select rotating cylinder Home Position Timeout Errror[I3.0],";
+CMFB;OP30B;I_STOP;102;" left front select rotating cylinder Sensor Miscompare[I3.0,I3.1],";
+CMFB;OP30B;I_STOP;103;" left front select pull in cylinder Work Position Timeout Errror[I3.3],";
+CMFB;OP30B;I_STOP;104;" left front select pull in cylinder Home Position Timeout Errror[I3.2],";
+CMFB;OP30B;I_STOP;105;" left front select pull in cylinder Sensor Miscompare[I3.2,I3.3],";
+CMFB;OP30B;I_STOP;106;" outside select prepull testing force not reach 1000N,";
+CMFB;OP30B;I_STOP;107;" outside select prepull testing cylinder Home Position Timeout Errror[I3.4],";
+CMFB;OP30B;I_STOP;108;" outside select prepull testing cylinder Sensor Miscompare[I3.4,I3.5],";
+CMFB;OP30B;I_STOP;109;" left outside lifting release cylinder Work Position Timeout Errror[I3.7],";
+CMFB;OP30B;I_STOP;110;" left outside lifting release cylinder Home Position Timeout Errror[I3.6],";
+CMFB;OP30B;I_STOP;111;" left outside lifting release cylinder Cylinder Sensor Miscompare[I3.6,I3.7],";
+CMFB;OP30B;I_STOP;112;" left outside select griping cylinder Work Position Timeout Errror[I4.1],";
+CMFB;OP30B;I_STOP;113;" left outside select griping cylinder Home Position Timeout Errror[I4.0],";
+CMFB;OP30B;I_STOP;114;" left outside select griping cylinder Sensor Miscompare[I4.0,I4.1],";
+CMFB;OP30B;I_STOP;115;" outside pullout testing cylinder Work Position Timeout Errror[I4.3],";
+CMFB;OP30B;I_STOP;116;" outside pullout testing cylinder Home Position Timeout Errror[I4.2],";
+CMFB;OP30B;I_STOP;117;" outside pullout testing cylinder Sensor Miscompare[I4.2,I4.3],";
+CMFB;OP30B;I_STOP;118;" left inside shift rotating cylinder Work Position Timeout Errror[I5.1],";
+CMFB;OP30B;I_STOP;119;" left inside shift rotating cylinder Home Position Timeout Errror[I5.0],";
+CMFB;OP30B;I_STOP;120;" left inside shift rotating cylinder Sensor Miscompare[I5.0,I5.1],";
+CMFB;OP30B;I_STOP;121;" left inside shift pull in cylinder Work Position Timeout Errror[I5.3],";
+CMFB;OP30B;I_STOP;122;" left inside shift pull in cylinder Home Position Timeout Errror[I5.2],";
+CMFB;OP30B;I_STOP;123;" left inside shift pull in cylinder Sensor Miscompare[I5.2,I5.3],";
+CMFB;OP30B;I_STOP;124;" Inside select prepull testing force not reach 1000N,";
+CMFB;OP30B;I_STOP;125;" Inside select prepull testing cylinder Home Position Timeout Errror[I5.4],";
+CMFB;OP30B;I_STOP;126;" Inside select prepull testing cylinder Sensor Miscompare[I5.4,I5.5],";
+CMFB;OP30B;I_STOP;127;" left inside lifting release cylinder Work Position Timeout Errror[I5.7],";
+CMFB;OP30B;I_STOP;128;" left inside lifting release cylinder Home Position Timeout Errror[I5.6],";
+CMFB;OP30B;I_STOP;129;" left inside lifting release cylinder Sensor Miscompare[I5.6,I5.7],";
+CMFB;OP30B;I_STOP;130;" left inside shift griping cylinder Work Position Timeout Errror[I6.1],";
+CMFB;OP30B;I_STOP;131;" left inside shift griping cylinder Home Position Timeout Errror[I6.0],";
+CMFB;OP30B;I_STOP;132;" left inside shift griping cylinder Sensor Miscompare[I6.0,I6.1],";
+CMFB;OP30B;I_STOP;133;" inside pullout testing cylinder Work Position Timeout Errror[I6.3],";
+CMFB;OP30B;I_STOP;134;" inside pullout testing cylinder Home Position Timeout Errror[I6.2],";
+CMFB;OP30B;I_STOP;135;" inside pullout testing cylinder Sensor Miscompare[I6.2,I6.3],";
+CMFB;OP30B;I_STOP;136;" right outside select pull in cylinder Work Position Timeout Errror[I7.1],";
+CMFB;OP30B;I_STOP;137;" right outside select pull in cylinder Home Position Timeout Errror[I7.0],";
+CMFB;OP30B;I_STOP;138;" right outside select pull in cylinder Sensor Miscompare[I7.0,I7.1],";
+CMFB;OP30B;I_STOP;139;" right outside lifting release cylinder Work Position Timeout Errror[I7.3],";
+CMFB;OP30B;I_STOP;140;" right outside lifting release cylinder Home Position Timeout Errror[I7.2],";
+CMFB;OP30B;I_STOP;141;" right outside lifting release cylinder Sensor Miscompare[I7.2,I7.3],";
+CMFB;OP30B;I_STOP;142;" right outside select griping the cylinder Work Position Timeout Errror[I7.5],";
+CMFB;OP30B;I_STOP;143;" right outside select griping the cylinder Home Position Timeout Errror[I7.4],";
+CMFB;OP30B;I_STOP;144;" right outside select griping the cylinder Sensor Miscompare[I7.4,I7.5],";
+CMFB;OP30B;I_STOP;145;" right outside select rotating cylinder Work Position Timeout Errror[I7.7],";
+CMFB;OP30B;I_STOP;146;" right outside select rotating cylinder Home Position Timeout Errror[I7.6],";
+CMFB;OP30B;I_STOP;147;" right outside select rotating cylinder Sensor Miscompare[I7.6,I7.7],";
+CMFB;OP30B;I_STOP;148;" left outside positioning cylinder Work Position Timeout Errror[I8.1],";
+CMFB;OP30B;I_STOP;149;" left outside positioning cylinder Home Position Timeout Errror[I8.0],";
+CMFB;OP30B;I_STOP;150;" left outside positioning cylinder Sensor Miscompare[I8.0,I8.1],";
+CMFB;OP30B;I_STOP;151;" right outside positioning cylinder Work Position Timeout Errror[I8.3],";
+CMFB;OP30B;I_STOP;152;" right outside positioning cylinder Home Position Timeout Errror[I8.2],";
+CMFB;OP30B;I_STOP;153;" right outside positioning cylinder Sensor Miscompare[I8.2,I8.3],";
+CMFB;OP30B;I_STOP;154;" right inside select rotating cylinder Work Position Timeout Errror[I9.1],";
+CMFB;OP30B;I_STOP;155;" right inside select rotating cylinder Home Position Timeout Errror[I9.0],";
+CMFB;OP30B;I_STOP;156;" right inside shift rotating cylinder Sensor Miscompare[I9.0,I9.1],";
+CMFB;OP30B;I_STOP;157;" right inside shift pull in cylinder Work Position Timeout Errror[I9.3],";
+CMFB;OP30B;I_STOP;158;" right inside shift pull in cylinder Home Position Timeout Errror[I9.2],";
+CMFB;OP30B;I_STOP;159;" right inside shift pull in cylinder Sensor Miscompare[I9.2,I9.3],";
+CMFB;OP30B;I_STOP;160;" right inside lifting release cylinder Work Position Timeout Errror[I9.5],";
+CMFB;OP30B;I_STOP;161;" right inside lifting release cylinder Home Position Timeout Errror[I9.4],";
+CMFB;OP30B;I_STOP;162;" right inside lifting release cylinder Sensor Miscompare[I9.4,I9.5],";
+CMFB;OP30B;I_STOP;163;" right inside shift griping the cylinder Work Position Timeout Errror[I9.7],";
+CMFB;OP30B;I_STOP;164;" right inside shift griping the cylinder Home Position Timeout Errror[I9.6],";
+CMFB;OP30B;I_STOP;165;" right inside shift griping the cylinder Sensor Miscompare[I9.6,I9.7],";
+CMFB;OP30B;I_STOP;166;" left inside postiton cylinder Work Position Timeout Errror[I10.1],";
+CMFB;OP30B;I_STOP;167;" left inside postiton cylinder Home Position Timeout Errror[I10.0],";
+CMFB;OP30B;I_STOP;168;" left inside postiton cylinder Sensor Miscompare[I10.0,I10.1],";
+CMFB;OP30B;I_STOP;169;" right inside positioning cylinder Work Position Timeout Errror[I10.3],";
+CMFB;OP30B;I_STOP;170;" right inside positioning cylinder Home Position Timeout Errror[I10.2],";
+CMFB;OP30B;I_STOP;171;" right inside positioning cylinder Sensor Miscompare[I10.2,I10.3]";
+CMFB;OP40A;C_STOP;101;Left Station Light Curtain Blocked(I2.0),;
+CMFB;OP40A;C_STOP;121;Machine Not At Home Position_L,;
+CMFB;OP40A;C_STOP;122;Auto Mode Not Selected_L,;
+CMFB;OP40A;C_STOP;125;The Part Of Left Station Is NOK,;
+CMFB;OP40A;C_STOP;140;detection pressure 1 sensor backcheck fault,;
+CMFB;OP40A;C_STOP;141;detection pressure 2 sensor backcheck fault,;
+CMFB;OP40A;C_STOP;142;shift terminal type sensor backcheck fault,;
+CMFB;OP40A;C_STOP;143;shift boot present sensor backcheck fault,;
+CMFB;OP40A;C_STOP;144;shift terminal present sensor backcheck fault,;
+CMFB;OP40A;C_STOP;145;shift terminal no present sensor backcheck fault,;
+CMFB;OP40A;C_STOP;146;select terminal present sensor backcheck fault,;
+CMFB;OP40A;C_STOP;147;select terminal no present sensor backcheck fault,;
+CMFB;OP40A;C_STOP;148;select boot present Backcheck Error,;
+CMFB;OP40A;C_STOP;149;Shift Terminal Type Confirmation Sensor_1 Backcheck Error,;
+CMFB;OP40A;C_STOP;150;Shift Terminal Type Confirmation Sensor_2 Backcheck Error,;
+CMFB;OP40A;C_STOP;151;Select Terminal Type Confirmation Sensor_1 Backcheck Error,;
+CMFB;OP40A;C_STOP;152;Select Terminal Type Confirmation Sensor_2 Backcheck Error,;
+CMFB;OP40A;C_STOP;153;select termianl type Backcheck Error,;
+CMFB;OP40A;C_STOP;154;detect steel wire present1 Backcheck Error,;
+CMFB;OP40A;C_STOP;155;detect steel wire present2 Backcheck Error;
+CMFB;OP40A;I_STOP;100;front clamping wire cylinder Work Position Timeout Errror[I3.1],;
+CMFB;OP40A;I_STOP;101;front clamping wire cylinder Home Position Timeout Errror[I3.0],;
+CMFB;OP40A;I_STOP;102;front clamping wire cylinder Sensor Miscompare[I3.0,I3.1],;
+CMFB;OP40A;I_STOP;103;back clamping wire cylinder Work Position Timeout Errror[I3.3],;
+CMFB;OP40A;I_STOP;104;back clamping wire cylinder Home Position Timeout Errror[I3.2],;
+CMFB;OP40A;I_STOP;105;back clamping wire cylinder Sensor Miscompare[I3.2,I3.3],;
+CMFB;OP40A;I_STOP;106;Select Wire Not Put Well[I3.5],;
+CMFB;OP40A;I_STOP;107;pushing select wire cylinder Home Position Timeout Errror[I3.4],;
+CMFB;OP40A;I_STOP;108;pushing select wire cylinder Sensor Miscompare[I3.4,I3.5],;
+CMFB;OP40A;I_STOP;109;crimping cylinder Work Position Timeout Errror[I5.0],;
+CMFB;OP40A;I_STOP;110;crimping cylinder Home Position Timeout Errror[I4.2],;
+CMFB;OP40A;I_STOP;111;crimping cylinder Cylinder Sensor Miscompare[I3.6,I3.7],;
+CMFB;OP40A;I_STOP;112;Shift Wire Not Put Well[I4.1],;
+CMFB;OP40A;I_STOP;113;pushing shift wire cylinder Home Position Timeout Errror[I4.0],;
+CMFB;OP40A;I_STOP;114;pushing shift wire cylinder Sensor Miscompare[I4.0,I4.1],;
+CMFB;OP40A;I_STOP;115;front cliping wire cylinder Work Position Timeout Errror[I4.3],;
+CMFB;OP40A;I_STOP;116;front cliping wire cylinder Home Position Timeout Errror[I4.2],;
+CMFB;OP40A;I_STOP;117;front cliping wire cylinder Sensor Miscompare[I4.2,I4.3],;
+CMFB;OP40A;I_STOP;118;back cliping wire cylinder Work Position Timeout Errror[I4.5],;
+CMFB;OP40A;I_STOP;119;back cliping wire cylinder Home Position Timeout Errror[I4.4],;
+CMFB;OP40A;I_STOP;120;back cliping wire cylinder Sensor Miscompare[I4.4,I4.5],;
+CMFB;OP40A;I_STOP;121;Grease Pump Pressure Alarm For Terminal[I8.7],;
+CMFB;OP40A;I_STOP;122;Grease valve1Home Position Timeout Errror[],;
+CMFB;OP40A;I_STOP;123;Grease valve1Sensor Miscompare[],;
+CMFB;OP40A;I_STOP;124;Grease Pump Pressure Alarm For Inner Member,;
+CMFB;OP40A;I_STOP;125;Grease valve2 Home Position Timeout Errror[],;
+CMFB;OP40A;I_STOP;126;Grease valve2 Sensor Miscompare[],;
+CMFB;OP40A;I_STOP;151;Emergency Stop Relay Not ON,;
+CMFB;OP40A;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP40B;C_STOP;101;Right Station Light Curtain Blocked(I2.6),;
+CMFB;OP40B;C_STOP;121;Machine Not At Home Position_R,;
+CMFB;OP40B;C_STOP;122;Auto Mode Not Selected_R,;
+CMFB;OP40B;C_STOP;125;The Part Of Right Station Is NOK,;
+CMFB;OP40B;C_STOP;140;shift omega present sensor backcheck fault,;
+CMFB;OP40B;C_STOP;141;select omega present sensor backcheck fault,;
+CMFB;OP40B;C_STOP;142;gromment present sensor backcheck fault,;
+CMFB;OP40B;C_STOP;143;detect steel wire present3 sensor backcheck fault,;
+CMFB;OP40B;C_STOP;144;detect steel wire present4 sensor backcheck fault,;
+CMFB;OP40B;C_STOP;148;Check Shift Wire Exists R sensor backcheck failure,;
+CMFB;OP40B;C_STOP;149;Check Select Wire Exists R sensor backcheck failure;
+CMFB;OP40B;I_STOP;100;Horizontal cylinder Work Position Timeout Error[I6.1],;
+CMFB;OP40B;I_STOP;101;Horizontal cylinder Home Position Timeout Error[I6.0],;
+CMFB;OP40B;I_STOP;102;Horizontal cylinder Sensors Miscompare Error[6.0,I6.1],;
+CMFB;OP40B;I_STOP;103;front Pressing wire cylinder Work Position Timeout Error[I6.3],;
+CMFB;OP40B;I_STOP;104;front Pressing wire cylinder Home Position Timeout Error[I6.2],;
+CMFB;OP40B;I_STOP;105;front Pressing wire cylinder Sensors Miscompare Error[I6.2,I6.3],;
+CMFB;OP40B;I_STOP;106;back Pressing wire cylinder Work Position Timeout Error[I6.5],;
+CMFB;OP40B;I_STOP;107;back Pressing wire cylinder Home Position Timeout Error[I6.4],;
+CMFB;OP40B;I_STOP;108;back Pressing wire cylinder Sensors Miscompare Error[6.4,I6.5],;
+CMFB;OP40B;I_STOP;109;Vertical Cylinder Work Position Timeout Error[I6.7],;
+CMFB;OP40B;I_STOP;110;Vertical Cylinder Home Position Timeout Error[I6.6],;
+CMFB;OP40B;I_STOP;111;Vertical Cylinder Sensors Miscompare Error[I6.6,I6.7],;
+CMFB;OP40B;I_STOP;112;Grease valve 3 Work Position Timeout Error[],;
+CMFB;OP40B;I_STOP;113;Grease valve 3 Home Position Timeout Error[],;
+CMFB;OP40B;I_STOP;114;Grease valve 3 Sensors Miscompare Error[],;
+CMFB;OP40B;I_STOP;115;Grease valve 4 Work Position Timeout Error[],;
+CMFB;OP40B;I_STOP;116;Grease valve 4 Home Position Timeout Error[],;
+CMFB;OP40B;I_STOP;117;Grease valve 4 Sensors Miscompare Error[],;
+CMFB;OP40B;I_STOP;151;Emergency Stop Relay Not ON,;
+CMFB;OP40B;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP50;C_STOP;101;Light Curtain Blocked(I2.0),;
+CMFB;OP50;C_STOP;121;Machine Not At Home Position,;
+CMFB;OP50;C_STOP;122;Auto Mode Not Selected,;
+CMFB;OP50;C_STOP;125;The Part Is NOK,;
+CMFB;OP50;C_STOP;132;select conduit present left Sensor Backcheck Error[7.6],;
+CMFB;OP50;C_STOP;133;select conduit present right Sensor Backcheck Error[7.7],;
+CMFB;OP50;C_STOP;134;terminal present Sensor Backcheck Error[8.2],;
+CMFB;OP50;C_STOP;140;check shift omega Sensor Backcheck Error[I3.2],;
+CMFB;OP50;C_STOP;141;check select omega Sensor Backcheck Error[I3.3],;
+CMFB;OP50;C_STOP;142;check shift rodt Sensor Backcheck Error[I3.4],;
+CMFB;OP50;C_STOP;143;check select rod Sensor Backcheck Error[I3.5],;
+CMFB;OP50;C_STOP;144;shift check omega Sensor Backcheck Error[I5.7],;
+CMFB;OP50;C_STOP;145;select check omega Sensor Backcheck Error[I6.7],;
+CMFB;OP50;C_STOP;146;shift conduit present left Sensor Backcheck Error[7.4],;
+CMFB;OP50;C_STOP;147;shift conduit present right Sensor Backcheck Error[7.5],;
+CMFB;OP50;C_STOP;148;Shift Terminal Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;149;Select Terminal Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;150;Heavy Mass Check Sensor 1 Backcheck Error,;
+CMFB;OP50;C_STOP;151;Heavy Mass Check Sensor 2 Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;152;Shift Swivel Tube Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;153;Select Swivel Tube Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;154;Shift Adjust Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;155;Select Adjust Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;156;Shift Star Sleve Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;157;Select Star Sleve Check Sensor Backcheck Error,;
+CMFB;OP50;C_STOP;158;Gromment Detect Check Sensor Backcheck Error;
+CMFB;OP50;I_STOP;100;crimping cylinder Work Position Timeout Errror[I3.1],;
+CMFB;OP50;I_STOP;101;crimping cylinder Home Position Timeout Errror[I3.0],;
+CMFB;OP50;I_STOP;102;crimping cylinderSensor Miscompare[I3.0,I3.1],;
+CMFB;OP50;I_STOP;103;left front location cylinder Work Position Timeout Errror[I4.1],;
+CMFB;OP50;I_STOP;104;left front location cylinder Home Position Timeout Errror[I4.0],;
+CMFB;OP50;I_STOP;105;left front location cylinder Sensor Miscompare[I4.0,I4.1],;
+CMFB;OP50;I_STOP;106;left back location cylinder Work Position Timeout Errror[I4.3],;
+CMFB;OP50;I_STOP;107;left back location cylinder Home Position Timeout Errror[I4.2],;
+CMFB;OP50;I_STOP;108;left back location cylinder Sensor Miscompare[I4.2,I4.3],;
+CMFB;OP50;I_STOP;109;right front location cylinder Work Position Timeout Errror[I4.5],;
+CMFB;OP50;I_STOP;110;right front location cylinder Home Position Timeout Errror[I4.4],;
+CMFB;OP50;I_STOP;111;right front location cylinder Sensor Miscompare[I4.4,I4.5],;
+CMFB;OP50;I_STOP;112;right back location cylinder Work Position Timeout Errror[I4.7],;
+CMFB;OP50;I_STOP;113;right back location cylinder Home Position Timeout Errror[I4.6],;
+CMFB;OP50;I_STOP;114;right back location cylinder Sensor Miscompare[I4.6,I4.7],;
+CMFB;OP50;I_STOP;115;select terminal pullout test cylinder Work Position Timeout Errror[I5.1],;
+CMFB;OP50;I_STOP;116;select terminal pullout test cylinder Not Reach 500N,;
+CMFB;OP50;I_STOP;117;select terminal pullout test cylinder Sensor Miscompare[I5.0,I5.1],;
+CMFB;OP50;I_STOP;118;selcet terminal fixed cylinder Work Position Timeout Errror[I5.3],;
+CMFB;OP50;I_STOP;119;selcet terminal fixed cylinder Home Position Timeout Errror[I5.2],;
+CMFB;OP50;I_STOP;120;selcet terminal fixed cylinder Sensor Miscompare[I5.2,I5.3],;
+CMFB;OP50;I_STOP;121;pulling select cable cylinder Work Position Timeout Errror[I5.5],;
+CMFB;OP50;I_STOP;122;pulling select cable cylinder Home Position Timeout Errror[I5.4],;
+CMFB;OP50;I_STOP;123;pulling select cable cylinder Sensor Miscompare[I5.4,I5.5],;
+CMFB;OP50;I_STOP;124;shift terminal pullout test cylinder Work Position Timeout Errror[I6.1],;
+CMFB;OP50;I_STOP;125;shift terminal pullout test cylinder Not Reach 500N,;
+CMFB;OP50;I_STOP;126;shift terminal pullout test cylinder Sensor Miscompare[I6.0,I6.1],;
+CMFB;OP50;I_STOP;127;shift terminal fixed cylinder Work Position Timeout Errror[I6.3],;
+CMFB;OP50;I_STOP;128;shift terminal fixed cylinder Home Position Timeout Errror[I6.2],;
+CMFB;OP50;I_STOP;129;shift terminal fixed cylinder Sensor Miscompare[I6.2,I6.3],;
+CMFB;OP50;I_STOP;130;pulling shift cable cylinder Work Position Timeout Errror[I6.5],;
+CMFB;OP50;I_STOP;131;pulling shift cable cylinder Home Position Timeout Errror[I6.4],;
+CMFB;OP50;I_STOP;132;pulling shift cable cylinder Sensor Miscompare[I6.4,I6.5],;
+CMFB;OP50;I_STOP;133;prepull shift cable cylinder Work Position Timeout Errror[I7.1],;
+CMFB;OP50;I_STOP;134;prepull shift cable cylinder Home Position Timeout Errror[I7.0],;
+CMFB;OP50;I_STOP;135;prepull shift cable cylinder Sensor Miscompare[I7.0,I7.1],;
+CMFB;OP50;I_STOP;136;prepull select cable cylinder Work Position Timeout Errror[I7.3],;
+CMFB;OP50;I_STOP;137;prepull select cable cylinder Home Position Timeout Errror[I7.2],;
+CMFB;OP50;I_STOP;138;prepull select cable cylinder Sensor Miscompare[I7.2,I7.3],;
+CMFB;OP50;I_STOP;139;terminal greasing valve Work Position Timeout Errror[I8.1],;
+CMFB;OP50;I_STOP;140;terminal greasing valve Home Position Timeout Errror[I8.0],;
+CMFB;OP50;I_STOP;141;terminal greasing valve Sensor Miscompare[I8.0,I8.1],;
+CMFB;OP50;I_STOP;161;Emergency Stop Relay Not ON,;
+CMFB;OP50;I_STOP;162;Emergency Stop Button Pressed;
+CMFB;OP55;C_STOP;102;Emergency Stop Relay Not ON,;
+CMFB;OP55;C_STOP;121;Machine Not At Home Position,;
+CMFB;OP55;C_STOP;122;Auto Mode Not Selected,;
+CMFB;OP55;C_STOP;125;Part NOK,;
+CMFB;OP55;C_STOP;140;Shift check1 Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;141;Shift check2 Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;142;Select check1 Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;143;Select check1 Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;149;Left_Select_Conduit_Placed_In_Place Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;150;Right_Shift_Conduit_Placed_In_Place Sensors Backcheck Error,;
+CMFB;OP55;C_STOP;151;Right_Select_Conduit_Placed_In_Place Sensors Backcheck Error;
+CMFB;OP55;I_STOP;101;Shift bushing assy cylinder Work Position Timeout Error [I3.3,Q3.1],;
+CMFB;OP55;I_STOP;102;Shift bushing assy cylinder Home Position Timeout Error [I3.2,Q3.0],;
+CMFB;OP55;I_STOP;103;Shift bushing assy cylinder Sensors Miscompare [I3.2,I3.3],;
+CMFB;OP55;I_STOP;104;Select bushing assy cylinder Work Position Timeout Error [I4.3,Q3.3],;
+CMFB;OP55;I_STOP;105;Select bushing assy cylinder Home Position Timeout Error [I4.2,Q3.2],;
+CMFB;OP55;I_STOP;106;Select bushing assy cylinder Sensors Miscompare [I4.2,I4.3],;
+CMFB;OP55;I_STOP;107;Shift test cylinder Work Position Timeout Error [I3.5,Q4.1],;
+CMFB;OP55;I_STOP;108;Shift test cylinder Home Position Timeout Error [I3.4,Q4.0],;
+CMFB;OP55;I_STOP;109;Shift test cylinder Sensors Miscompare [I3.4,I3.5],;
+CMFB;OP55;I_STOP;110;Select test cylinder Work Position Timeout Error [I4.3,Q4.3],;
+CMFB;OP55;I_STOP;111;Select test cylinder Home Position Timeout Error [I4.2,Q4.2],;
+CMFB;OP55;I_STOP;112;Select test cylinder Sensors Miscompare [I4.2,I4.3],;
+CMFB;OP55;I_STOP;113;Conduit clamp cylinder Work Position Timeout Error [I4.7,Q4.5],;
+CMFB;OP55;I_STOP;114;Conduit clamp cylinder Home Position Timeout Error [I4.6,Q4.4],;
+CMFB;OP55;I_STOP;115;Conduit clamp cylinderCylinder Sensors Miscompare [I4.6,I4.7],;
+CMFB;OP55;I_STOP;116;Screw feeder cylinder Work Position Timeout Error [5.1,Q7.3],;
+CMFB;OP55;I_STOP;117;Screw feeder cylinder Home Position Timeout Error [I5.0,Q7.2],;
+CMFB;OP55;I_STOP;118;Screw feeder cylinder Cylinder Sensors Miscompare [I5.0,I5.1],;
+CMFB;OP55;I_STOP;124;Screw NOK,;
+CMFB;OP55;I_STOP;125;IAI Error,;
+CMFB;OP55;I_STOP;126;Shift Screw test Error,;
+CMFB;OP55;I_STOP;127;Select Screw test Error,;
+CMFB;OP55;I_STOP;128;Shift washer assembly not correct,;
+CMFB;OP55;I_STOP;129;Selcet washer assembly not correct,;
+CMFB;OP55;I_STOP;130;Part Pullout Testing Not OK,;
+CMFB;OP55;I_STOP;131;Screw operation Timeout Error,;
+CMFB;OP55;I_STOP;151;Emergency Stop Relay Not ON,Pls Press Reset Button.,;
+CMFB;OP55;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP60;C_STOP;121;Machine Not At Home Position,;
+CMFB;OP60;C_STOP;122;Auto Mode Not Selected,;
+CMFB;OP60;C_STOP;123;No Model Selected,;
+CMFB;OP60;C_STOP;125;Outside select terminal check1 Sensor Backcheck Error[I3.2],;
+CMFB;OP60;C_STOP;126;Outside select terminal check2 Sensor Backcheck Error[I3.3],;
+CMFB;OP60;C_STOP;127;Outside select termianl present1 Sensor Backcheck Error[I3.4],;
+CMFB;OP60;C_STOP;128;Outside select termianl present2 Sensor Backcheck Error[I3.5],;
+CMFB;OP60;C_STOP;129;Outside select omega present1 Sensor Backcheck Error[I3.6],;
+CMFB;OP60;C_STOP;130;Outside shift terminal check1 Sensor Backcheck Error[I4.2],;
+CMFB;OP60;C_STOP;131;Outside shift terminal check2 Sensor Backcheck Error[I4.3],;
+CMFB;OP60;C_STOP;132;Outside shift termianl present1 Sensor Backcheck Error[I4.4],;
+CMFB;OP60;C_STOP;133;Outside shift omega present1 Sensor Backcheck Error[I4.5],;
+CMFB;OP60;C_STOP;134;Outside shift conduit present Sensor Backcheck Error[I5.2],;
+CMFB;OP60;C_STOP;135;Outside select conduit present Sensor Backcheck Error[I5.3],;
+CMFB;OP60;C_STOP;136;Inside shift conduit present Sensor Insidecheck Error[I5.6],;
+CMFB;OP60;C_STOP;137;Inside select conduit present Sensor Backcheck Error[I5.7],;
+CMFB;OP60;C_STOP;138;Outside select omega present Sensor Backcheck Error[I6.0],;
+CMFB;OP60;C_STOP;139;Outside select tube present Sensor Backcheck Error[I6.1],;
+CMFB;OP60;C_STOP;140;Outside select adjuster check1 Sensor Backcheck Error[I6.2],;
+CMFB;OP60;C_STOP;141;Outside select adjuster check2 Sensor Backcheck [I6.3],;
+CMFB;OP60;C_STOP;142;Outside shift omega present Sensor Backcheck Error[I6.4],;
+CMFB;OP60;C_STOP;143;Outside shift tube present Sensor Backcheck Error[I6.5],;
+CMFB;OP60;C_STOP;144;Outside shift adjuster check1 Sensor Backcheck Error[I6.6],;
+CMFB;OP60;C_STOP;145;Outside shift adjuster check2 Sensor Backcheck Error[I6.7],;
+CMFB;OP60;C_STOP;146;Inside select terminal check1 Sensor Backcheck Error[I7.2],;
+CMFB;OP60;C_STOP;147;Inside select terminal check2 Sensor Backcheck Error[I7.3],;
+CMFB;OP60;C_STOP;148;Inside select termianl present1 Sensor Backcheck Error[I7.4],;
+CMFB;OP60;C_STOP;149;Inside select termianl present2 Sensor Backcheck [I7.5],;
+CMFB;OP60;C_STOP;150;Inside select omega present1 Sensor Backcheck Error[I7.6],;
+CMFB;OP60;C_STOP;151;Inside shift terminal check1 Sensor Insidecheck Error[I8.2],;
+CMFB;OP60;C_STOP;152;Inside shift terminal check2 Sensor Insidecheck Error[I8.3],;
+CMFB;OP60;C_STOP;153;Inside shift termianl present Sensor Insidecheck Error[I8.4],;
+CMFB;OP60;C_STOP;154;Inside shift omega present1 Sensor Insidecheck Error[I8.5],;
+CMFB;OP60;C_STOP;155;Inside select omega present2 Sensor Backcheck Error[I9.0],;
+CMFB;OP60;C_STOP;156;Inside select tube present Sensor Backcheck Error[I9.1],;
+CMFB;OP60;C_STOP;157;Insideselect adjuster check1 Sensor Backcheck Error[I9.2],;
+CMFB;OP60;C_STOP;158;Inside select adjuster check2 Sensor Backcheck Error[I9.3],;
+CMFB;OP60;C_STOP;159;Inside shift omega present2 Sensor Insidecheck Error[I9.4],;
+CMFB;OP60;C_STOP;160;Inside shift tube present Sensor Insidecheck Error[I9.5],;
+CMFB;OP60;C_STOP;161;Inside shift adjuster check1 Sensor Insidecheck Error[I9.6],;
+CMFB;OP60;C_STOP;162;Inside shift adjuster check2 Sensor Insidecheck Error[I9.7];
+CMFB;OP60;I_STOP;101;Outside select release cylinder Work Position Timeout[I3.1],;
+CMFB;OP60;I_STOP;102;Outside select release cylinder Home Position Timeout[I3.0],;
+CMFB;OP60;I_STOP;103;Outside select release cylinder Sensors Miscompare[I3.0,I3.1],;
+CMFB;OP60;I_STOP;104;Outside shift release cylinder Work Position Timeout[I4.1],;
+CMFB;OP60;I_STOP;105;Outside shift release cylinder Home Position Timeout[I4.0],;
+CMFB;OP60;I_STOP;106;Outside shift release cylinder Sensors Miscompare[I4.0,I4.1],;
+CMFB;OP60;I_STOP;107;Outside clamp conduit cylinder Work Position Timeout[I5.1],;
+CMFB;OP60;I_STOP;108;Outside clamp conduit cylinder Home Position Timeout[I5.0],;
+CMFB;OP60;I_STOP;109;Outside clamp conduit cylinder Sensors Miscompare[I5.0,I5.1],;
+CMFB;OP60;I_STOP;110;Inside select release cylinder Work Position Timeout[I5.5],;
+CMFB;OP60;I_STOP;111;Inside select release cylinder Home Position Timeout[I5.4],;
+CMFB;OP60;I_STOP;112;Inside select release cylinder Sensors Miscompare[I5.4,I5.5],;
+CMFB;OP60;I_STOP;113;Inside shift release cylinder Work Position Timeout[I7.1],;
+CMFB;OP60;I_STOP;114;Inside shift release cylinder Home Position Timeout[I7.0],;
+CMFB;OP60;I_STOP;115;Inside shift release cylinder Sensors Miscompare[I7.0,I7.1],;
+CMFB;OP60;I_STOP;116;Inside clamp conduit cylinder Work Position Timeout[I8.1],;
+CMFB;OP60;I_STOP;117;Inside clamp conduit cylinder Home Position Timeout[I8.0],;
+CMFB;OP60;I_STOP;118;Inside clamp conduit cylinder Sensors Miscompare[I8.0,I8.1],;
+CMFB;OP60;I_STOP;119;Outside Selectlength_Axis Alarm,;
+CMFB;OP60;I_STOP;120;Outside Shiftlength_Axis Alarm,;
+CMFB;OP60;I_STOP;121;Outside SelectA+B_Axis Alarm,;
+CMFB;OP60;I_STOP;122;Outside ShiftA+B_Axis Alarm,;
+CMFB;OP60;I_STOP;123;Inside Selectlength_Axis Alarm,;
+CMFB;OP60;I_STOP;124;Inside Shiftlength_Axis Alarm,;
+CMFB;OP60;I_STOP;125;Inside SelectA+B_Axis Alarm,;
+CMFB;OP60;I_STOP;126;Inside ShiftA+B_Axis Alarm,;
+CMFB;OP60;I_STOP;127;Lazer_Axis Alarm,;
+CMFB;OP60;I_STOP;135;Light Curtain Blocked In Cycle,;
+CMFB;OP60;I_STOP;136;Before Select Cable A+B Test, Force Reach Stop Force, Please Check,;
+CMFB;OP60;I_STOP;137;Before Shift Cable A+B Test, Force Reach Stop Force, Please Check,;
+CMFB;OP60;I_STOP;140;Select Cable Axis Alarm,;
+CMFB;OP60;I_STOP;141;Shift Cable Axis Alarm,;
+CMFB;OP60;I_STOP;142;Outside Part Select Cable Friction Test Failed,Please Check,;
+CMFB;OP60;I_STOP;143;Outside Part Shift Cable Friction Test Failed,Please Check,;
+CMFB;OP60;I_STOP;144;Inside Part Select Cable Friction Test Failed,Please Check,;
+CMFB;OP60;I_STOP;145;Inside Part Shift Cable Friction Test Failed,Please Check,;
+CMFB;OP60;I_STOP;151;Emergency Stop Relay Not ON,;
+CMFB;OP60;I_STOP;152;Emergency Stop Button Pressed;
+CMFB;OP70;C_STOP;102;Emergency Stop Relay Not ON,;
+CMFB;OP70;C_STOP;121;Machine Not At Home Position,;
+CMFB;OP70;C_STOP;122;Auto Mode Not Selected,;
+CMFB;OP70;C_STOP;125;Part NOK,;
+CMFB;OP70;C_STOP;133;select adjuster present Sensors Backcheck Error[I5.4],;
+CMFB;OP70;C_STOP;134;shift right omega present Sensors Backcheck Error[I5.5],;
+CMFB;OP70;C_STOP;135;shift right clip present Sensors Backcheck Error[I5.6],;
+CMFB;OP70;C_STOP;136;slect adjuster locker present Sensors Backcheck Error[I5.7],;
+CMFB;OP70;C_STOP;137;gromment present Sensors Backcheck Error[I6.0],;
+CMFB;OP70;C_STOP;141;select omega present Sensors Backcheck Error[I3.4],;
+CMFB;OP70;C_STOP;142;select clip present Sensors Backcheck Error[I3.5],;
+CMFB;OP70;C_STOP;143;shift clip present Sensors Backcheck Error[I3.6],;
+CMFB;OP70;C_STOP;144;shift omega present Sensors Backcheck Error[I3.7],;
+CMFB;OP70;C_STOP;145;select star sleeve present Sensors Backcheck Error[I4.6],;
+CMFB;OP70;C_STOP;146;shift star sleeve present Sensors Backcheck Error[I4.7],;
+CMFB;OP70;C_STOP;147;select right omega present Sensors Backcheck Error[I5.2],;
+CMFB;OP70;C_STOP;148;select right clip present Sensors Backcheck Error[I5.3];
+CMFB;;MANUAL;;;Zoradenie
+CMFB;;MANUAL;;;Zmena_typu
+CMFB;;MANUAL;;;Chyba_material
+CMFB;;MANUAL;;;Zastavene_QE
+CMFB;;MANUAL;;;Zastavene_PE
+CMFB;;MANUAL;;;Nedostatok_operatorov
+CMFB;;MANUAL;;;Odstavka
\ No newline at end of file
diff --git a/flow/repository.json b/flow/repository.json
new file mode 100644
index 0000000..29fb290
--- /dev/null
+++ b/flow/repository.json
@@ -0,0 +1 @@
+{"$1634465281992ram":[{"timestamp":1634480076668,"ram":60.69,"ram_max":249}]}
\ No newline at end of file
diff --git a/flow/show_dbdata.js b/flow/show_dbdata.js
new file mode 100644
index 0000000..4c6cb86
--- /dev/null
+++ b/flow/show_dbdata.js
@@ -0,0 +1,228 @@
+exports.id = 'showdb';
+exports.title = 'Show db data';
+exports.group = 'Worksys';
+exports.color = '#888600';
+exports.version = '1.0.2';
+exports.icon = 'sign-out';
+exports.input = 5;
+exports.output = 1;
+
+
+exports.install = async function(instance) {
+
+ instance.on("0", _ => {
+ instance.send(0, FLOW.GLOBALS.settings);
+ })
+ instance.on("1", _ => {
+ instance.send(0, FLOW.GLOBALS.relaysData);
+ })
+ instance.on("2", _ => {
+ instance.send(0, FLOW.GLOBALS.nodesData);
+ })
+ instance.on("3", _ => {
+ instance.send(0, FLOW.GLOBALS.pinsData);
+ })
+ instance.on("4", _ => {
+ instance.send(0, {rpcSwitchOffLine, rpcSetNodeDimming, rpcLineProfile, rpcNodeProfile, sunCalcExample, dataFromTerminalBroadcast})
+ })
+};
+
+
+
+const rpcSwitchOffLine =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 8,
+ "method": "set_command",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "edb_line",
+ "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
+ }
+ ],
+ "command": "switch",
+ "payload": {
+ "value": false
+ }
+ }
+ }
+ }
+}
+
+const rpcSetNodeDimming =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 10,
+ "method": "set_command",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "street_luminaire",
+ "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
+ }
+ ],
+ "command": "dimming",
+ "payload": {
+ "value": 5
+ }
+ }
+ }
+ }
+}
+
+const rpcLineProfile =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 9,
+ "method": "set_profile",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "edb_line",
+ "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
+ }
+ ],
+ "payload": {
+ "intervals": [
+ {
+ "value": 0,
+ "end_time": "20:00",
+ "start_time": "13:00"
+ },
+ {
+ "value": 1,
+ "end_time": "05:30",
+ "start_time": "20:00"
+ },
+ {
+ "value": 0,
+ "end_time": "13:00",
+ "start_time": "05:30"
+ }
+ ],
+ "astro_clock": true,
+ "dawn_lux_sensor": false,
+ "dusk_lux_sensor": false,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 0,
+ "dusk_astro_clock_offset": 0,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+ }
+ }
+ }
+ }
+}
+
+
+const rpcNodeProfile =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 11,
+ "method": "set_profile",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "street_luminaire",
+ "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
+ }
+ ],
+ "payload": {
+ "intervals": [
+ {
+ "cct": 3000,
+ "value": 0,
+ "end_time": "17:50",
+ "start_time": "13:00"
+ },
+ {
+ "cct": 3000,
+ "value": 100,
+ "end_time": "21:30",
+ "start_time": "17:50"
+ },
+ {
+ "cct": 3000,
+ "value": 0,
+ "end_time": "13:00",
+ "start_time": "07:10"
+ },
+ {
+ "cct": 3000,
+ "value": 50,
+ "end_time": "00:00",
+ "start_time": "21:30"
+ },
+ {
+ "cct": 3000,
+ "value": 10,
+ "end_time": "04:30",
+ "start_time": "00:00"
+ },
+ {
+ "cct": 3000,
+ "value": 100,
+ "end_time": "07:10",
+ "start_time": "04:30"
+ }
+ ],
+ "astro_clock": true,
+ "dawn_lux_sensor": false,
+ "dusk_lux_sensor": false,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 30,
+ "dusk_astro_clock_offset": 20,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+ }
+ }
+ }
+ }
+}
+
+ const sunCalcExample = {
+ dusk_no_offset: '20:18',
+ dawn_no_offset: '05:19',
+ dusk: '20:18',
+ dusk_hours: 20,
+ dusk_minutes: 18,
+ dawn: '05:19',
+ dawn_hours: 5,
+ dawn_minutes: 19,
+ dusk_time: 1715278688962,
+ dawn_time: 1715224744357,
+ dusk_astro_clock_offset: 0,
+ dawn_astro_clock_offset: 0
+}
+
+
+const dataFromTerminalBroadcast = {
+ address: 4294967295,
+ byte1: 0,
+ byte2: 0,
+ byte3: 0,
+ byte4: 96,
+ name: "Time Schedule settings",
+ recipient: 2,
+ register: 8,
+ rw: 1
+}
diff --git a/flow/slack_connector.js b/flow/slack_connector.js
deleted file mode 100644
index 8c073a6..0000000
--- a/flow/slack_connector.js
+++ /dev/null
@@ -1,124 +0,0 @@
-exports.id = 'slack_connector';
-exports.title = 'Slack_Connector';
-exports.version = '1.0.0';
-exports.group = 'Worksys';
-exports.color = '#888600';
-exports.input = 1;
-exports.output = 1;
-exports.click = false;
-exports.author = 'Jakub Klena';
-exports.icon = 'sign-out';
-exports.options = { slack_channel: "C071KN2Q8SK", api_key: "", bot_name: "Flow DEMO", bot_icon: ":totaljs:" };
-// Slack channel - where to post the messages, can be name like "backend-alerts"
-// Bot Name - Name of the "user" that will post these messages, it should be based on which server it is running on.
-// Bot Icon - We can use any slack icon (even custom ones uploaded by us) as the "user" profile picture
-
-exports.html = ``;
-
-exports.readme = `Sends any string received on input to Slack Channel.`;
-
-var log4js = require("log4js");
-var path = require('path');
-
-log4js.configure({
- appenders: {
- errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
- console: { type: 'console' }
- },
- categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
- }
-});
-
-const errLogger = log4js.getLogger("errLogs");
-const logger = log4js.getLogger();
-const monitor = log4js.getLogger("monitorLogs");
-
-exports.install = function(instance) {
- var can = false;
-
- process.on('uncaughtException', function (err) {
- errLogger.error('uncaughtException:', err.message);
- errLogger.error(err.stack);
- instance.error(err);
- });
-
- instance.on('data', function(data) {
- if (!can) return;
-
- let str = String(data.data); // Ensuring data get converted to string
- let message = {
- 'channel': instance.options.slack_channel,
- 'username': instance.options.bot_name,
- 'icon_emoji': instance.options.bot_icon,
- 'text': str
- };
- let headers = {
- 'Content-type': `application/json`,
- 'Authorization': `Bearer ${instance.options.api_key}`
- };
-
- if (F.is4) {
- let opt = {
- 'method': 'post',
- 'url': 'https://slack.com/api/chat.postMessage',
- 'headers': headers,
- 'body': JSON.stringify(message),
- 'type': 'json',
- 'callback': function(err, response) {
- if (response && !err) {
- var msg = { data: response.body, status: response.status, headers: response.headers, host: response.host, cookies: response.cookies };
- instance.send2(msg);
- } else if (err) {
- errLogger.error('Slack post failed - err:', err, '\n - response was:', response);
- instance.error(err, response);
- }
- }
- };
- REQUEST(opt);
-
- } else {
- U.request('https://slack.com/api/chat.postMessage', ['json', 'post'], JSON.stringify(message), function(err, data, status, headers, host) {
- if (response && !err) {
- response.data = { data: data, status: status, headers: headers, host: host };
- instance.send2(response);
- } else if (err) {
- errLogger.error('Slack post failed - err:', err, '\n - response was:', response);
- instance.error(err, response);
- }
- }, null, headers);
- }
- });
-
- instance.reconfigure = function() {
- var options = instance.options;
- can = options.slack_channel && options.bot_name && options.bot_icon && options.api_key ? true : false;
- instance.status(can ? '' : 'Not configured', can ? undefined : 'red');
- };
-
- instance.on('options', instance.reconfigure);
- instance.reconfigure();
-}
diff --git a/flow/slack_filter.js b/flow/slack_filter.js
deleted file mode 100644
index a27c9e1..0000000
--- a/flow/slack_filter.js
+++ /dev/null
@@ -1,187 +0,0 @@
-exports.id = 'slack_filter';
-exports.title = 'Slack Filter';
-exports.group = 'Citysys';
-exports.color = '#30E193';
-exports.input = 1;
-exports.output = 1;
-exports.author = 'Jakub Klena';
-exports.icon = 'plug';
-exports.version = '1.0.8';
-exports.options = { 'name':'', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes':'["is responding again"]', 'tag_on_include':'[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel':'' };
-
-exports.html = `
-
-
-
@(Name of this server)
-
-
-
@(Slack channel to receive the alerts)
-
-
-
@(Watch these types, comma separated names)
-
-
-
@(Watch messages that include any of the following strings)
-
-
-
@(Tag people if message includes something)
-
-
-
`;
-
-exports.readme = `# Slack Filter`;
-
-exports.install = function(instance) {
- var running = false;
- instance["savedSlackMessages"] = [];
- var timer = null;
-
- instance.on('data', function(response) {
- if (!running) return;
- let value = response.data;
- if (typeof value !== 'object') return;
-
- let can = false
- var k = Object.keys(value);
- var interested = JSON.parse(instance.options.types);
- var msg_incl = JSON.parse(instance.options.message_includes);
- var tags = JSON.parse(instance.options.tag_on_include);
-
- if (k.length <= 0) return;
- if (value[k[0]].length <= 0) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0], 'values')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values'], '_event')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'type')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'source')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event']['source'], 'func')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'message')) return;
- if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'message_data')) return;
-
- let icon = ':totaljs:';
- let type = value[k[0]][0]['values']['_event']['type'];
- let source = value[k[0]][0]['values']['_event']['source']['func'];
- let message = value[k[0]][0]['values']['_event']['message'];
- let message_data = value[k[0]][0]['values']['_event']['message_data'];
- let tag = '';
-
- switch(type){
- case 'debug':
- icon = ':beetle:';
- break;
- case 'info':
- icon = ':speech_balloon:';
- break;
- case 'notice':
- icon = ':speech_balloon:';
- break;
- case 'warning':
- icon = ':exclamation:';
- break;
- case 'alert':
- icon = ':warning:';
- break;
- case 'error':
- icon = ':no_entry:';
- break;
- case 'emergency':
- icon = ':fire:';
- break;
- case 'critical':
- icon = ':fire:';
- break;
- }
-
- // Check if this message includes one of the strings we are watching for
- for (const msg of msg_incl){
- if (message.includes(msg)){
- if (msg == 'is responding again') icon = ':large_green_circle:';
- can = true;
- break;
- }
- }
- // Check if message is one of the types we are watching for
- if (interested.includes(type)){
- can = true;
- }
-
- if (!can) return;
-
-
- // Check for each person tags based on what the message includes
- for (const person of tags){
- for (const msg of person.includes){
- if (message.includes(msg)){
- tag += '<@'+person.user_id+'> ';
- break; // Break out from this person checks as they are already tagged now
- }
- }
- }
- // Now that all people are tagged add new line symbol
- if (tag != '') tag += '\n';
-
- let send_data = tag+instance.options.name+' '+type.toUpperCase()+'\n*Source*: '+source+'\n*Message*: '+message;
- if (message_data) {
- send_data += '\nData: '+message_data;
- }
-
- let ignore_msg = false
- if (message.includes('Configuration of dimming profile to node no')){
- for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
- if (FLOW["savedSlackMessages"][i].message == message){
- ignore_msg = true;
- break;
- }
- }
- if (!ignore_msg){
- FLOW["savedSlackMessages"].push({message, 'dateandtime': Date.now()});
- if (timer === null){
- timer = setTimeout(checkSavedMessages, 60*60000);
- }
- }
- }
-
- if (!ignore_msg){
- instance.send2({'msg':send_data,'bot_name':instance.options.name+' '+type.toUpperCase(),'bot_icon':icon,'channel':instance.options.slack_channel});
- }
- });
-
- function checkSavedMessages(){
- var d = Date.now();
- d = d - 86400000; // older then 24hr
- var a = [];
- //Remove msgs older then 24hr
- for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
- if (FLOW["savedSlackMessages"][i].dateandtime > d){
- a.push(FLOW["savedSlackMessages"][i]);
- }
- }
- FLOW["savedSlackMessages"] = a;
-
- if (FLOW["savedSlackMessages"].length > 0) {
- timer = setTimeout(checkSavedMessages, 60*60000);
- } else {
- timer = null;
- }
- }
-
- instance.reconfigure = function() {
- try {
- if (!FLOW["savedSlackMessages"]){
- FLOW["savedSlackMessages"] = [];
- }
-
- if (instance.options.name) {
- instance.status('Running');
- running = true;
- } else {
- instance.status('Please enter name', 'red');
- running = false;
- }
- } catch (e) {
- instance.error('Citysys connector: ' + e.message);
- }
- };
-
- instance.on('options', instance.reconfigure);
- instance.reconfigure();
-};
\ No newline at end of file
diff --git a/flow/test.js b/flow/test.js
new file mode 100644
index 0000000..f0ca813
--- /dev/null
+++ b/flow/test.js
@@ -0,0 +1,120 @@
+const getTimezoneOffset = (timeZone, date = new Date()) => {
+ const tz = date.toLocaleString("en", {timeZone, timeStyle: "long"}).split(" ").slice(-1)[0];
+ const dateString = date.toString();
+ const offset = Date.parse(`${dateString} UTC`) - Date.parse(`${dateString} ${tz}`);
+
+ // return UTC offset in millis
+ return offset;
+}
+
+let profile = {
+ "time_points": [
+ {
+ "start_time": "13:00",
+ "value": 0
+ },
+ {
+ "start_time": "16:00",
+ "value": 1
+ }
+ ],
+ "astro_clock": true,
+ "dusk_astro_clock_offset": 0,
+ "dawn_astro_clock_offset": 0,
+ "dusk_lux_sensor": false,
+ "dawn_lux_sensor": false,
+ "dusk_lux_sensor_value": 5,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_lux_sensor_time_window": 30,
+ }
+
+ let now = new Date(); // Creates a Date Object using the clients current time
+ console.log(now, now.getTime());
+
+ //let [hours, minutes, seconds] = "18:19:02".split(':');
+ //d.setHours(+hours); // Set the hours, using implicit type coercion
+//d.setMinutes(minutes); // You can pass Number or String. It doesn't really matter
+//d.setSeconds(seconds);
+
+ let time_points = profile.time_points;
+ time_points.push( {"start_time": "1:00", "value": 1} );
+
+ time_points.sort(function (a, b) {
+
+ let [ahours, aminutes, aseconds] = a.start_time.split(':');
+ let [bhours, bminutes, bseconds] = b.start_time.split(':');
+
+ let ad = new Date();
+ ad.setHours( parseInt(ahours) );
+ ad.setMinutes( parseInt(aminutes) );
+ ad.setSeconds(0);
+
+ let bd = new Date();
+ bd.setHours( parseInt(bhours) );
+ bd.setMinutes( parseInt(bminutes) );
+ ad.setSeconds(0);
+
+ return ad.getTime() - bd.getTime();
+ });
+
+ console.log(time_points);
+
+ let value = time_points[ time_points.length - 1].value;
+
+ for(let i = 0; i < time_points.length; i++)
+ {
+ let [hours, minutes, seconds] = time_points[i].start_time.split(':');
+
+ let start_time = new Date();
+ start_time.setHours( parseInt(hours) );
+ start_time.setMinutes( parseInt(minutes) );
+ start_time.setSeconds(0);
+
+ if(now.getTime() > start_time.getTime())
+ {
+ value = time_points[i].value;
+ }
+
+ //console.log(start_time);
+ }
+
+ console.log(value);
+
+ const offset = getTimezoneOffset("Europe/Bratislava");
+console.log(offset);
+
+
+function removeTask(obj)
+{
+
+ let keys = Object.keys(obj);
+ tasks = tasks.filter((task) => {
+
+ let counter = 0;
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+ if(task.hasOwnProperty(key) && obj.hasOwnProperty(key))
+ {
+ if(task[key] == obj[key]) counter++;
+ }
+
+ }
+
+ if(counter == keys.length) return false;
+ return true;
+
+ });
+
+}
+
+function convertUTCDateToLocalDate(date) {
+ var newDate = new Date(date);
+ newDate.setMinutes(date.getMinutes() - date.getTimezoneOffset());
+ return newDate;
+}
+
+let d = convertUTCDateToLocalDate(new Date("2022-04-26T06:56:54.000Z"));
+
+console.log(d, d.getHours());
diff --git a/flow/thermometer.js b/flow/thermometer.js
index 1a5714f..5bde34b 100644
--- a/flow/thermometer.js
+++ b/flow/thermometer.js
@@ -1,220 +1,99 @@
-exports.id = 'thermometer';
-exports.title = 'Thermometer';
-exports.group = 'Worksys';
-exports.color = '#5CB36D';
-exports.version = '1.0.3';
-exports.output = ["red", "white", "blue"];
-exports.author = 'Rastislav Kovac';
-exports.icon = 'thermometer-three-quarters';
-
-exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`;
-
-const instanceSendTo = {
- debug: 0,
- tb: 1,
- dido_controller: 2
-}
-
-//read temperature - frequency
-let timeoutMin = 5;//minutes
-
-var path = require('path');
-var log4js = require("log4js");
-
-log4js.configure({
- appenders: {
- errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
- console: { type: 'console' }
- },
- categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
- }
-});
-
-const errLogger = log4js.getLogger("errLogs");
-const logger = log4js.getLogger();
-const monitor = log4js.getLogger("monitorLogs");
-
-//logger.debug("text")
-//monitor.info('info');
-//errLogger.error("some error");
-
-const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper');
-const dbSettings = TABLE("settings");
-let temperatureAddress = "";
-
-async function loadSettings()
-{
- //todo global FLOW.OMS_edgeName is making problem, so we load it here as well, it should not be
- let responseSettings = await promisifyBuilder(dbSettings.find());
- temperatureAddress = responseSettings[0]["temperature_adress"];
-}
-
-loadSettings();
-
-
-exports.install = function(instance) {
-
- const { exec } = require('child_process');
- const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter');
-
- let startRead;
- let dataToTb;
- let counter = 0;
-
- let edgeName = "";
-
-
- logger.debug(exports.title, "installed");
-
- instance.on("close", function(){
- clearInterval(startRead);
- })
-
-
- const start = function() {
-
- try {
-
- if(FLOW.OMS_controller_type === "unipi")
- {
- clearInterval(startRead);
- return;
- }
-
- if(temperatureAddress === "") throw "gettemperature: temperatureAddress is not defined";
-
- logger.debug("FLOW.OMS_temperature_adress", FLOW.OMS_temperature_adress);
-
- exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
-
- edgeName = FLOW.OMS_edgeName;
-
- if(edgeName !== "")
- {
- if(error)
- {
-
- if(FLOW.OMS_brokerready == undefined)
- {
- logger.debug("gettemparature - FLOW.OMS_brokerready is undefined");
-
- setTimeout(function(){
- start();
- }, 3000);
-
- return;
- }
-
- if(FLOW.OMS_brokerready)
- {
- //sendNotification("start", edgeName, ERRWEIGHT.WARNING, "Thermometer is not responding", {"Error": error}, instanceSendTo.tb, instance, "thermometer");
- sendNotification("start", edgeName, "thermometer_is_not_responding", {}, {"Error": error}, instanceSendTo.tb, instance, "thermometer");
- }
-
- let status = "NOK";
- dataToTb = {
- [edgeName]: [
- {
- "ts": Date.now(),
- "values": {
- "status": status
- }
- }
- ]
- }
-
- monitor.info("Thermometer is not responding", error, FLOW.OMS_brokerready);
-
- // instance.send(instanceSendTo.tb, dataToTb); // poslat stav nok do tb, ak to handluje dido_controller ??
- instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"});
- }
- else parseData(stdout);
- }
- else
- {
- monitor.info("gettemperature: edgeName is not defined", FLOW.OMS_edgeName);
-
- setTimeout(function(){
- start();
- }, 3000);
-
- return;
- }
-
-
- //instance.send({"Temp":stdout,"stderr":stderr,"err":error});
- });
-
- }
- catch(err) {
- errLogger.error(exports.title, err);
- }
- }
-
- const parseData = function(data) {
-
- data = parseFloat(data);
-
- logger.debug("gettemperature", data);
-
- if(!isNaN(data)) {
-
- if(counter > 290)
- {
- instance.send(instanceSendTo.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break");
-
- //sendNotification("parseData", edgeName, ERRWEIGHT.NOTICE, "Thermometer is working again", "", instanceSendTo.tb, instance, "thermometer");
- if(FLOW.OMS_brokerready) sendNotification("parseData", edgeName, "thermometer_is_responding_again", {}, "", instanceSendTo.tb, instance, "thermometer");
- }
-
- logger.debug("gettemperature", data);
- const values = {
- "temperature": Number(data.toFixed(2)),
- "status": "OK"
- }
-
- dataToTb = {
- [edgeName]: [
- {
- "ts": Date.now(),
- "values":values
- }
- ]
- }
-
- instance.send(instanceSendTo.tb, dataToTb);
- instance.send(instanceSendTo.dido_controller, values);
-
- counter = 0;
-
- } else {
-
- counter++;
- monitor.info("gettemperature err", counter, data);
-
- //ked je problem 1 den
- let day = 24 * 60 / timeoutMin;
- if ( counter > day && counter < day + 2 ) {
- //sendNotification("parseData", edgeName, ERRWEIGHT.WARNING, "Thermometer receives invalid data", "", instanceSendTo.tb, instance, "thermometer");
- sendNotification("parseData", edgeName, "thermometer_sends_invalid_data", {}, "", instanceSendTo.tb, instance, "thermometer");
-
- instance.send(instanceSendTo.debug, "[Get temperature component] - no temperature data from RVO for more than 1 day");
- instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"});
- }
-
- }
-
- }
-
- setTimeout(function(){
- start();
- }, 15000);
-
- startRead = setInterval(start, timeoutMin * 1000 * 60);
-
-};
\ No newline at end of file
+exports.id = 'thermometer';
+exports.title = 'Thermometer';
+exports.group = 'Worksys';
+exports.color = '#5CB36D';
+exports.input = 1;
+exports.version = '1.0.3';
+exports.output = ["red", "white", "blue"];
+exports.icon = 'thermometer-three-quarters';
+
+exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`;
+
+const { errLogger, logger, monitor } = require('./helper/logger');
+
+const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ dido_controller: 2
+}
+
+//read temperature - frequency
+let timeoutMin = 1;//minutes
+let NUMBER_OF_FAILURES_TO_SEND_ERROR = 3;
+
+exports.install = function(instance) {
+
+ const { exec } = require('child_process');
+ const { sendNotification } = require('./helper/notification_reporter');
+
+ let startRead;
+ let counter = 0;
+ let rvoTbName = "";
+ let temperatureAddress = "";
+
+ logger.debug(exports.title, "installed");
+
+ instance.on("close", function(){
+ clearInterval(startRead);
+ })
+
+
+ const main = function() {
+
+ try {
+
+ if(temperatureAddress === "") throw "Thermometer: temperatureAddress is not defined";
+
+ exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
+ debugger;
+error = 1;
+ if(!error)
+ {
+ parseData(stdout)
+ return;
+ }
+
+ counter++;
+ if(counter == NUMBER_OF_FAILURES_TO_SEND_ERROR) sendNotification("Thermometer_main", rvoTbName, "thermometer_is_not_responding", {}, {"Error": error}, SEND_TO.tb, instance, "thermometer");
+ monitor.info("Thermometer is not responding", error);
+ instance.send(SEND_TO.dido_controller, {status: "NOK-thermometer"});
+ });
+
+ }
+ catch(err) {
+ errLogger.error(exports.title, err);
+ clearInterval(startRead);
+ }
+ }
+
+ const parseData = function(data) {
+
+ data = parseFloat(data);
+ logger.debug("Thermometer", data);
+
+ if(isNaN(data)) {
+ errLogger.error("Thermometer sends invalid data");
+ return;
+ }
+
+ if(counter > NUMBER_OF_FAILURES_TO_SEND_ERROR) //1 hour
+ {
+ instance.send(SEND_TO.debug, "Thermometer - temperature data are comming again");
+ sendNotification("Thermometer_parseData", rvoTbName, "thermometer_is_responding_again", {}, "", SEND_TO.tb, instance, "thermometer");
+ }
+
+ const values = {
+ "temperature": Number(data.toFixed(2)),
+ }
+
+ instance.send(SEND_TO.dido_controller, {values: values});
+ counter = 0;
+ }
+
+ instance.on("data", _ => {
+ temperatureAddress = FLOW.GLOBALS.settings.temperature_address;
+ rvoTbName = FLOW.GLOBALS.settings.rvoTbName;
+ startRead = setInterval(main, timeoutMin * 1000 * 60);
+ main();
+ })
+};
diff --git a/flow/wsmqttpublish.js b/flow/wsmqttpublish.js
index 794fedc..4f155e9 100644
--- a/flow/wsmqttpublish.js
+++ b/flow/wsmqttpublish.js
@@ -4,30 +4,28 @@ exports.group = 'MQTT';
exports.color = '#888600';
exports.version = '1.0.2';
exports.icon = 'sign-out';
-exports.input = 1;
+exports.input = 2;
exports.output = ["red", "white", "blue"];
exports.author = 'Daniel Segeš';
exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
-exports.npm = ['mqtt'];
-
exports.html = `
-
-
-
Hostname or IP address (if not empty - setting will override db setting)
-
-
-
-
+
+
+
Hostname or IP address (if not empty - setting will override db setting)
+
+
+
+
`;
@@ -41,21 +39,22 @@ Added:
- rpc response
`;
-const instanceSendTo = {
+const { promisifyBuilder } = require('./helper/db_helper');
+const { errLogger, monitor } = require('./helper/logger');
+const fs = require('fs');
+const mqtt = require('mqtt');
+
+const SEND_TO = {
debug: 0,
rpcCall: 1,
services: 2
}
-const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
-
//CONFIG
-let useLog4js = true;
let createTelemetryBackup = true;
let saveTelemetryOnError = true;//backup_on_failure overrides this value
//------------------------
-var fs = require('fs');
let rollers;
if(createTelemetryBackup) rollers = require('streamroller');
@@ -64,51 +63,18 @@ let insertNoSqlCounter = 0;
let insertBackupNoSqlCounter = 0;
let processingData = false;
-let backup_on_failure = false;//== saveTelemetryOnError - create backup broker send failure
+let backup_on_failure = false;//== saveTelemetryOnError - create backup client send failure
let restore_from_backup = 0; //how many rows process at once?
let restore_backup_wait = 0;//wait seconds
let lastRestoreTime = 0;
-let errLogger;
-let logger;
-let monitor;
-
-if(useLog4js)
-{
- var path = require('path');
- var log4js = require("log4js");
-
- log4js.configure({
- appenders: {
- errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
- console: { type: 'console' }
- },
- categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
- }
- });
-
- errLogger = log4js.getLogger("errLogs");
- logger = log4js.getLogger();
- monitor = log4js.getLogger("monitorLogs");
-
- //USAGE
- //logger.debug("text");
- //monitor.info('info');
- //errLogger.error("some error");
-}
+// if there is an error in client connection, flow logs to monitor.txt. Not to log messages every second, we use sendClientError variable
+let sendClientError = true;
process.on('uncaughtException', function (err) {
- if(errLogger)
- {
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
- }
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
//TODO
//send to service
@@ -122,13 +88,9 @@ const nosqlBackup = NOSQL('/backup/tbdata');
exports.install = function(instance) {
- var broker;
+ var client;
var opts;
- var brokerready = false;
-
- instance.on('options', loadSettings);
-
- mqtt = require('mqtt');
+ var clientReady = false;
// wsmqtt status for notification purposes on projects.worksys.io database
let wsmqttName = null;
@@ -137,21 +99,28 @@ exports.install = function(instance) {
function getWsmqttName(host)
{
- if(host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
- else if(host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
- else if(host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
+ if(host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
+ else if(host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
+ else if(host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
}
function sendWsStatus()
{
- instance.send(instanceSendTo.services, {[wsmqttName]: wsmqtt_status});
+ instance.send(SEND_TO.services, {[wsmqttName]: wsmqtt_status});
}
- sendWsStatusVar = setInterval(sendWsStatus, 180000);
+ function main()
+ {
+ if(!FLOW.dbLoaded) return;
+
+ loadSettings();
+ clearInterval(sendWsStatus);
+ sendWsStatusVar = setInterval(sendWsStatus, 180000);
+ }
//set opts according to db settings
- async function loadSettings()
+ function loadSettings()
{
if(instance.options.host !== "")
@@ -174,21 +143,17 @@ exports.install = function(instance) {
else
{
- const dbSettings = TABLE("settings");
- let responseSettings = await promisifyBuilder(dbSettings.find());
-
- backup_on_failure = responseSettings[0]["backup_on_failure"];
+ const SETTINGS = FLOW.GLOBALS.settings;
+ backup_on_failure = SETTINGS.backup_on_failure;
saveTelemetryOnError = backup_on_failure;
- restore_from_backup = responseSettings[0]["restore_from_backup"];
- restore_backup_wait = responseSettings[0]["restore_backup_wait"];
+ restore_from_backup = SETTINGS.restore_from_backup;
+ restore_backup_wait = SETTINGS.restore_backup_wait;
- let mqtt_host = responseSettings[0]["mqtt_host"];
- let mqtt_clientid = responseSettings[0]["mqtt_clientid"];
- let mqtt_username = responseSettings[0]["mqtt_username"];
- let mqtt_port = responseSettings[0]["mqtt_port"];
-
- console.log("wsmqttpublich -> loadSettings from db", responseSettings[0]);
+ let mqtt_host = SETTINGS.mqtt_host;
+ let mqtt_clientid = SETTINGS.mqtt_clientid;
+ let mqtt_username = SETTINGS.mqtt_username;
+ let mqtt_port = SETTINGS.mqtt_port;
opts = {
host: mqtt_host,
@@ -211,74 +176,78 @@ exports.install = function(instance) {
var url = "mqtt://" + opts.host + ":" + opts.port;
console.log("MQTT URL: ", url);
- broker = mqtt.connect(url, opts);
+ client = mqtt.connect(url, opts);
- broker.on('connect', function() {
+ client.on('connect', function() {
instance.status("Connected", "green");
- monitor.info("MQTT broker connected");
+ monitor.info("MQTT client connected");
- brokerready = true;
- FLOW.OMS_brokerready = brokerready;
+ sendClientError = true;
+ clientReady = true;
wsmqtt_status = 'connected';
});
- broker.on('reconnect', function() {
+ client.on('reconnect', function() {
instance.status("Reconnecting", "yellow");
- brokerready = false;
-
- FLOW.OMS_brokerready = brokerready;
+ clientReady = false;
});
- broker.on('message', function(topic, message) {
+ client.on('message', function(topic, message) {
// message is type of buffer
message = message.toString();
if (message[0] === '{') {
TRY(function() {
message = JSON.parse(message);
+console.log("ooooo------x", message);
if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
- broker.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
- instance.send(instanceSendTo.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
+ client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
+ instance.send(SEND_TO.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
}
}, () => instance.debug('MQTT: Error parsing data', message));
}
- instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message });
+ instance.send(SEND_TO.rpcCall, {"topic":topic, "content":message });
});
- broker.on('close', function(err) {
- brokerready = false;
- FLOW.OMS_brokerready = brokerready;
+ client.on('close', function(err) {
+ clientReady = false;
wsmqtt_status = 'disconnected';
if (err && err.toString().indexOf('Error')) {
instance.status("Err: "+err.code, "red");
- instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
} else {
instance.status("Disconnected", "red");
- instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts });
+ instance.send(SEND_TO.debug, {"message":"Client CLOSE signal received !", "error":err, "opt":opts });
}
- broker.reconnect();
+ client.reconnect();
});
- broker.on('error', function(err) {
+ client.on('error', function(err) {
instance.status("Err: "+ err.code, "red");
- instance.send(instanceSendTo.debug, {"message":"Broker ERROR signal received !", "error":err, "opt":opts });
- monitor.info('MQTT broker error', err);
-
- brokerready = false;
- FLOW.OMS_brokerready = brokerready;
+ instance.send(SEND_TO.debug, {"message":"Client ERROR signal received !", "error":err, "opt":opts });
+ if(sendClientError) {
+ monitor.info('MQTT client error', err);
+ sendClientError = false;
+ }
+ clientReady = false;
wsmqtt_status = 'disconnected';
-
});
}
- instance.on('data', function(data) {
- if (brokerready)
+ instance.on("0", _ => {
+ main();
+ })
+
+
+ instance.on('1', function(data) {
+
+ if(clientReady)
{
//do we have some data in backup file?
//if any, process data from database
@@ -287,13 +256,12 @@ exports.install = function(instance) {
//read telemetry data and send back to server
if(!processingData) processDataFromDatabase();
}
-
}
- if (brokerready)
+ if(clientReady)
{
let stringifiedJson = JSON.stringify(data.data);
- broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
+ client.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
//backup telemetry
if(createTelemetryBackup)
@@ -318,8 +286,8 @@ exports.install = function(instance) {
else
{
- if(logger) logger.debug("Broker unavailable. Data not sent !", data.data);
- instance.send(instanceSendTo.debug, {"message":"Broker unavailable. Data not sent !", "data": data.data });
+ //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
+ instance.send(SEND_TO.debug, {"message":"Client unavailable. Data not sent !", "data": data.data });
if(saveTelemetryOnError)
{
@@ -335,9 +303,9 @@ exports.install = function(instance) {
});
- instance.close = function(done) {
- if (brokerready){
- broker.end();
+ instance.close = function(done) {
+ if(clientReady){
+ client.end();
clearInterval(sendWsStatusVar);
}
};
@@ -364,7 +332,7 @@ exports.install = function(instance) {
let firstDigit = files[i].slice(0, pos);
fileCounter = parseInt(firstDigit);
- if (isNaN(fileCounter)) fileCounter = 0;
+ if(isNaN(fileCounter)) fileCounter = 0;
//console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
if(type == "max")
@@ -434,10 +402,7 @@ exports.install = function(instance) {
const processDataFromDatabase = async () => {
- if(restore_from_backup <= 0)
- {
- return;
- }
+ if(restore_from_backup <= 0) return;
//calculate diff
const now = new Date();
@@ -469,7 +434,7 @@ exports.install = function(instance) {
for(let i = 0; i < records.length; i++)
{
- if (brokerready) {
+ if(clientReady) {
let item = records[i];
let id = item.id;
@@ -478,18 +443,18 @@ exports.install = function(instance) {
{
//console.log("------------processDataFromDatabase - remove", id, dataBase, i);
- try{
+ try {
let o = JSON.parse(JSON.stringify(item));
delete o.id;
let message = JSON.stringify(o);
- broker.publish("v1/gateway/telemetry", message, {qos:1});
+ client.publish("v1/gateway/telemetry", message, {qos:1});
//remove from database
await promisifyBuilder(nosql.remove().where("id", id));
- } catch (error) {
+ } catch(error) {
//process error
console.log("processDataFromDatabase", error);
}
@@ -524,8 +489,6 @@ exports.install = function(instance) {
}
- loadSettings();
-
- //instance.on('options', instance.reconfigure);
- //instance.reconfigure();
+ instance.on('options', main);
+ //instance.reconfigure();
};