From 86619fbcff6e45630bf2a897565fe6444a8de4ee Mon Sep 17 00:00:00 2001 From: rasta5man Date: Sat, 13 Apr 2024 20:29:31 +0200 Subject: [PATCH] Actual flowserver on Senica rvo --- config | 3 +- databases/modbus_config.js | 113 + databases/nodes.table | 77 +- databases/notifications.table | 10 +- databases/pins.table | 28 +- databases/relays.table | 8 +- databases/settings.table | 2 +- flow/cmd_manager.js | 8152 ++++++++--------- flow/designer.json | 918 +- flow/designer_deploy.json | 1516 --- ...di_do_controller.js => dido_controller.js} | 616 +- flow/gettemperature.js | 40 +- flow/helper/ErrorToServiceHandler.js | 246 +- flow/helper/notification_reporter.js | 270 +- flow/infosender.js | 20 +- flow/modbus_citysys.js | 1127 --- flow/modbus_reader.js | 336 + flow/monitorcpu.js | 107 - flow/mqtt.js | 441 - flow/mqtt_listener.js | 171 - flow/mqttpublish.js | 134 - flow/mqttsubscribe.js | 168 - flow/nosql.js | 191 - flow/relays.js | 357 - flow/test.js | 120 - flow/thermometer.js | 220 + flow/wsmqttpublish.js | 148 +- package.json | 12 +- saved_data/modbus_settings | 135 - 29 files changed, 5833 insertions(+), 9853 deletions(-) create mode 100644 databases/modbus_config.js delete mode 100644 flow/designer_deploy.json rename flow/{di_do_controller.js => dido_controller.js} (74%) delete mode 100644 flow/modbus_citysys.js create mode 100644 flow/modbus_reader.js delete mode 100644 flow/monitorcpu.js delete mode 100644 flow/mqtt.js delete mode 100644 flow/mqtt_listener.js delete mode 100644 flow/mqttpublish.js delete mode 100644 flow/mqttsubscribe.js delete mode 100644 flow/nosql.js delete mode 100644 flow/relays.js delete mode 100644 flow/test.js create mode 100644 flow/thermometer.js delete mode 100644 saved_data/modbus_settings diff --git a/config b/config index 80f7778..b10cd71 100644 --- a/config +++ b/config @@ -1,4 +1,5 @@ name : Total.js Flow +default_timezone : Europe/Bratislava // Packages settings package#flow (Object) : { url: '/' } @@ -7,5 +8,5 @@ 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.pins : pin:number|type:string|line:number +table.pins : pin:string|type:string|line:number table.notifications : key:string|weight:string|sk:string|en:string diff --git a/databases/modbus_config.js b/databases/modbus_config.js new file mode 100644 index 0000000..d63430f --- /dev/null +++ b/databases/modbus_config.js @@ -0,0 +1,113 @@ +const timeoutInterval = 300000; +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 }; diff --git a/databases/nodes.table b/databases/nodes.table index 38fe2d5..57331db 100644 --- a/databases/nodes.table +++ b/databases/nodes.table @@ -1,48 +1,31 @@ node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean -+|697|joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM|3||1|1|........... -+|659|Ymn9oleRxJ0vw17WzAyGwdyEBk4ObdMXj2VgpNLG|3||1|1|........... -+|636|M6ogKQW09bOXewAYvZyvJqyJrV1aRnPGE37p42Nx|2||1|1|........... -+|648|gaMGN4x1e9JlZz0QPRDd9Rym6dVr3OpvqKnoWBbk|2||1|1|........... -+|664|oGVzxNWP9lrjaQ7vKODQ7g51gqp62YZREmdw3XBM|1||1|1|........... -+|634|NGWamnYqlP1wbgrZQxDAWm5e2X7OVAK69koR04vL|2||1|1|........... -+|670|dlE1VQjYrNx9gZRmb38g1YyoLBO4qaAk2M6JPnG7|2||1|1|........... -+|641|vnmG4kJxaXWNBgMQq0D7Mz5e9oZzOAlr6LdR3w2V|2||1|1|........... -+|632|LpkVlmq4b3jMwJQxBZ8aM78rXAP6o97Ke0aOYEg2|2||1|1|........... -+|667|MzXBoWbEZjO0lrpqnRyoJ4DkmVeaNAGdL9g4QKxP|1||1|1|........... -+|682|vnreBJ6PMqgz20pYEL82XQyG1jkWwdQxZVNAOlmK|1||1|1|........... -+|643|oZmYXEbw9lVWRv1jLxDe9bDdgAMz4PKQnNJ6eB23|1||1|1|........... -+|642|pEonaKBOGbj9034MgJ8W3G8qXvxNWVkAPQz21R6L|1||1|1|........... -+|647|BLQal6Pn9oz1KmNgek5Yqd50vd2MAbqG3OV7Rp4j|1||1|1|........... -+|646|4agVJ9dPQkmp1R2X3EDJKxyrK6ZlNoM0n7qxBOev|1||1|1|........... -+|666|9PpgLEnvk4WMV6RmOJybMGDaeAXzo2BQNG3K17Zw|1||1|1|........... -+|654|Mmp93b2nvd7OoqgBeEyEZq5kjlAV1Y4ZNXwW0zLG|1||1|1|........... -+|637|koW06PeGrLlBp2YJQE5Ogw5RmMaXKzj3wOAZg9n7|3||1|1|........... -+|680|KL2jNOVpdARa9XvoeJDPga8bkmPBxqn7Ww3gzGQ1|1|{"intervals":[{"cct":3000,"value":100,"end_time":"13:40","start_time":"13:00"},{"cct":3000,"value":-1,"end_time":"13:50","start_time":"13:40"},{"cct":3000,"value":100,"end_time":"13:00","start_time":"13: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}|1|0|........... -+|645|jklN4JpQAx362o9XYZDN6wDgrWw1P7GEbdBM0vRV|1||1|1|........... -+|660|gj7zbKV46oQ1p2e0AJ8XqZDG3YNWaRrlOEXvBxmM|3||1|1|........... -+|669|Y9aLW03wOZkABvKXbMyL0lyV1xdNj72r4egqGRzJ|3|{"intervals":[{"cct":3000,"value":0,"end_time":"13:40","start_time":"13:00"},{"cct":3000,"value":100,"end_time":"07:20","start_time":"13:50"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"07:20"},{"cct":3000,"value":0,"end_time":"13:50","start_time":"13: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|........... -+|671|AvVdgzYJZaPx3oMqeED4Oj8NnmKkw716bRO90jLB|3||1|1|........... -+|638|9xgzG4Op1BrKZPmoQkDrmj8E73ndJNMjavAwX2Re|3||1|1|........... -+|639|BOjEzGRZ46bnp9wa2A8z76D0JkmW1QPNdrqevXVL|3||1|1|........... -+|693|KjbN4q7JPZmexgdnz2yKdn5YAWwO0Q3BMX6ERLoV|2|{"intervals":[{"cct":3000,"value":0,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":100,"end_time":"22:10","start_time":"20:00"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"05:30"},{"cct":3000,"value":30,"end_time":"02:40","start_time":"22:10"},{"cct":3000,"value":90,"end_time":"05:30","start_time":"02:40"}],"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|........... -+|649|0p2rwdP7aGoOQLJNgAynJNy6xWXbmMe3nvZqlzkV|1|{"intervals":[{"cct":3000,"value":100,"end_time":"13:40","start_time":"13:00"},{"cct":3000,"value":-1,"end_time":"13:50","start_time":"13:40"},{"cct":3000,"value":100,"end_time":"13:00","start_time":"13: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}|1|1|........... -+|698|mYnBzbeGaAL62jowRv59M35Xq9QpZ0K7O1dg4xVl|1||1|1|........... -+|640|WjBL12pg63eX4N9P7zy0XYyEJKmlbkGwZMx0avQV|2||1|1|........... -+|656|BrQx3NGKgVMRaXYAo9y1GE8ZzkWnj1le6bdOLE20|1|{"intervals":[{"cct":3000,"value":100,"end_time":"13:40","start_time":"13:00"},{"cct":3000,"value":-1,"end_time":"13:50","start_time":"13:40"},{"cct":3000,"value":100,"end_time":"13:00","start_time":"13: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}|1|1|........... -+|651|qaAOzENGrvpbe0VoK7D6Ld519PZmdg3nl24JLQMk|2||1|1|........... -+|691|lekrmdvO0BQG1ZW4AV8jzq8M39xnN2wEbRgPjXLp|1||1|1|........... -+|661|laYK7Pomn2bNZXEpedDxAqyOJkQ3WwV49gqxLrAR|3|{"intervals":[{"cct":3000,"value":0,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":60,"end_time":"05:30","start_time":"20:00"},{"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|........... -+|665|gbv4nzqxW0XGAPKVNk8kr25ZQ2l3O6LRBprM97ew|3||1|1|............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... -+|662|gbv4nzqxW0XGAPKVNk8kW48ZQ2l3O6LRBprM97ew|3|{"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}|1|1|........... -+|668|lekrmdvO0BQG1ZW4AV8jeZ5M39xnN2wEbRgPjXLp|3|{"intervals":[{"cct":3000,"value":0,"end_time":"13:10","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"12:50","start_time":"13:10"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"12: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}|1|1|............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ -+|689|q0rElBPdL6kxMAjnzVDRl95emNZY7oOv2wK9gb31|3|{"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}|1|1|........... -+|683|XKQbz3WAwY21dGa0R453rWyJm9PZOjqlvpr6Nkeo|3|{"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}|1|1|........... -+|688|PaGbQ3wBAZWOmRvK9VDpvz5endLJYopEqlkzNMxX|3|{"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}|1|1|........... -+|672|0XYElWeKBNJn1gdoMG8lON5ALkPvj4V3xra2q6mO|2||1|1|................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. -+|690|wGjQobgOK0n2YqBZmVDVR3DR9ep6EXA1ka3vzlP7|2||1|1|.............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. -+|692|l9YkRpoB2vVa0mKqEO8ZGGDjW43eXnJML6GxzbwQ|2|{"intervals":[{"cct":3000,"value":0,"end_time":"13:10","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"12:50","start_time":"13:10"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"12: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}|1|1|............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ -+|655|RMgnK93rkoAazbqdQ4yBYpDZ1YXGx6pmwBeVEP2O|2||1|1|.............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. -+|694|Jm32GR1qpwQxlZza0N5mE15AP96YbOKLogrXVW4e|2|{"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}|1|1|........... -+|635|Vq2JaWpw1OdBKmNeoj8w605XE40l3kgL76Azb9QP|2|{"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}|1|1|........... -+|650|0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO|3|{"intervals":[{"cct":3000,"value":0,"end_time":"13:10","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"12:50","start_time":"13:10"},{"cct":3000,"value":0,"end_time":"13:00","start_time":"12: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}|1|1|........... -+|663|LpkVlmq4b3jMwJQxBZ8akayrXAP6o97Ke0aOYEg2|1|{"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}|0|1|........... ++|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|........... diff --git a/databases/notifications.table b/databases/notifications.table index aa0552c..b207fe7 100644 --- a/databases/notifications.table +++ b/databases/notifications.table @@ -25,8 +25,10 @@ key:string|weight:string|sk:string|en:string +|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|............... +|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_is_not_responding|ERROR|Elektromer neodpovedá|Electrometer is not responding|............... -+|no_voltage_detected_on_phase|CRITICAL|Na fáze č. ${phase} nie je napätie|No voltage detected on phase no. ${phase}|............... -+|electrometer_is_responding_again|NOTICE|Elektromer znovu odpovedá|Electrometer is responding again|............... -+|voltage_on_phase_has_been_restored|NOTICE|Napätie na fáze č. ${phase} bolo obnovené|Voltage on phase no. ${phase} has been restored|............... ++|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|............... ++|electrometer_ok|NOTICE|Elektromer znovu odpovedá|Electrometer is responding again|............... ++|no_voltage_on_phase|CRITICAL|Na fáze č. ${phase} nie je napätie|No voltage detected on phase no. ${phase}|............... ++|voltage_on_phase_restored|NOTICE|Napätie na fáze č. ${phase} bolo obnovené|Voltage on phase no. ${phase} has been restored|............... +|flow_start|NOTICE|FLOW bol spustený|FLOW has been started |............... ++|twilight_sensor_nok|ERROR|Sensor súmraku neodpovedá|Twilight sensor is not responding|............... ++|twilight_sensor_ok|NOTICE|Sensor súmraku znovu odpovedá|Twilight sensor is responding again|............... \ No newline at end of file diff --git a/databases/pins.table b/databases/pins.table index be299ec..f08ec54 100644 --- a/databases/pins.table +++ b/databases/pins.table @@ -1,14 +1,14 @@ -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|........... +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|........... diff --git a/databases/relays.table b/databases/relays.table index c21f5b2..68e4f06 100644 --- a/databases/relays.table +++ b/databases/relays.table @@ -1,5 +1,5 @@ line:number|tbname:string|contactor:number|profile:string -+|0|KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV|1||........... -+|3|vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V|0||.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... -+|1|RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O|0|{"intervals":[{"value":0,"end_time":"13:00","start_time":"13:00"}],"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|dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7|0||................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ ++|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}|........... diff --git a/databases/settings.table b/databases/settings.table index d87a74e..a182df5 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 -+|testpanel|en|28.427B45920702|48.70826502|17.28455203|192.168.252.4|showroom_test_panel_led|xmRd6RJxW53WZe4vMFLU|1883|0|1|lm|ttymxc4|1|20|5|........................................... ++|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|........................................... diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 1b708af..c1efd18 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -1,4169 +1,3983 @@ -exports.id = 'cmd_manager'; -exports.title = 'CMD Manager'; -exports.group = 'Worksys'; -exports.color = '#5D9CEC'; -exports.version = '0.0.4'; -exports.output = ['red', 'blue', 'yellow', 'blue', 'white']; - -//blue - send message to relays - -exports.input = true; -exports.author = 'Daniel Segeš'; -exports.icon = 'cloud-upload'; -//exports.npm = ['serialport' , 'child_process']; - -exports.html = ` -
-
-
-
RPC - run RPC calls

-
-
-
@(User)
-
-
-
@(Password)
-
-
-
@(My edge)
-
-
-
-`; - -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 } = require('./helper/db_helper.js'); -const { sendNotification, initNotifications, ERRWEIGHT } = require('./helper/notification_reporter.js'); - -//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'); - -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"); - -//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 - -//set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime - - -//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 -let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89]; - -//1 - dimming - -const dbNodes = TABLE("nodes"); -const dbRelays = TABLE("relays"); -const dbSettings = TABLE("settings"); - -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 -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" - //params.tbname = tbname; - params.priority = priorityTypes.node_cmd;//default priority - params.timestamp = 0;//execution time - if(priority != undefined ) - { - params.timestamp = priority; - params.priority = priority; - } - - params.addMinutesToTimestamp = 0;//repeat if > 0, - - //params.isDusk = false; - //params.isDawn = false; - //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.log("", "settings", responseSettings[0], "-------------------------------------"); - logger.debug('settings', responseSettings[0]); - - //FLOW.OMS_tem - //rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number - - initNotifications(); -} - -//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) {} - - //test reset profilu - //nodeProfile = undefined; - - logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile); - //return; - - //let timestamp = priorityTypes.node_cmd; - - //let now = new Date(); - //now.setSeconds(now.getSeconds() + 10); - //let timestamp = now.getTime(); - - let timestamp = priorityTypes.node_cmd; - - //nodeProfile = undefined; - 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(priorityTypes.node_cmd); - params.type = "set_node_profile"; - params.address = node; - params.byte1 = 0; - params.byte2 = 0; - params.byte3 = 0; - params.byte4 = 32; - 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", "", instanceSendTo.tb, instance ); - } - else - { - let tasksProfile = []; - //cmdCounter[node] = tasksProfile.length; - //tasks.push(tasksProfile); - - //let timestamp = priorityTypes.node_cmd; - - //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu - let params = getParams(priorityTypes.node_cmd); - params.type = "set_node_profile"; - params.address = node; - params.byte1 = 0; - params.byte2 = 0; - params.byte3 = 0; - params.byte4 = 32; - 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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(profile.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); - -} - -const instanceSendTo = { - debug: 0, - tb: 1, - http_response: 2, - di_do_controller: 3, - infoSender: 4 -} - -const priorityTypes = { - 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 -} - - -let interval = null;//timeout for procesing tasks -let refFlowdata = null;//holds reference to httprequest flowdata -let refFlowdataObj = {}; - -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 ]; - } - } -} - -let tasks = [];//list of command calls to process - -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; - - }); - -} - - -//TODO - to remove? -const shortIterval = 10; -const longInterval = 100; - -loadSettings(); - -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); - }) - - //te();//force error - - const tbHandler = new DataToTbHandler(instanceSendTo.tb); - tbHandler.setSender(exports.title); - - //FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name - //const errorHandler = new ErrorToServiceHandler(instance, instanceSendTo.infoSender); - errorHandler.setProjectsId(FLOW.OMS_projects_id); - //const errorHandler = new ErrorToServiceHandler(instance); - //errorHandler.sendMessageToService("ahoj", 0); - - - async function loadRelaysData(line) - { - logger.debug("loadRelaysData", line); - - //ak zapiname liniu, mali by sme skontrolovat kde processed je false - //nodes.table: node:number|tbname:string|line:number|profile:string|processed:boolean - //vyselektujem vsetky nodes a spracujem profil - - return new Promise((resolve, reject) => { - - dbRelays.find().make(function(builder) { - builder.callback(function(err, response) { - - if(err != null) reject(err); - - let relaysDataTmp = {}; - for(let i = 0; i < response.length; i++) - { - let record = response[i]; - let line = record["line"]; - relaysDataTmp[ record["line"] ] = record; - - //porovname predchadzajuce hodnoty - //ak record.contactor == 1, a aktualna hodnota record.contactor == 0 - //to znamena, ze sa zmenil stav - linia bola vypnuta - - let prevData = relaysData[ record["line"] ]; - - //ugly but do not remove!!! - relaysData[ record["line"] ] = record; - - let state = "";//on, off or empty (no change) - if(prevData != undefined) - { - /* - if(prevData.contactor == 1 && record.contactor == 0) - { - state = "off"; - reportOfflineNodeStatus(line); - } - - if(prevData.contactor == 0 && record.contactor == 1) - { - state = "on"; - reportOnlineNodeStatus(line); - } - */ - - } - else - { - //start flowu - state = "start"; - } - - if(line != undefined) - { - //ak sa jedna o update profilu linie - pozor di_co_controller posiela command pre loadRelaysData - if(line != record["line"] ) continue; - } - - //je zapnuta linia? contactor = 1 a processed = false, spracujeme profil - if(record.contactor == 1) - { - - //nespracovany profil, zapisem do nodu - //rotary_switch_state = Automatic - profilu pre nody sa vykonavaju - //ak je spracovany, a automatic - tak ho zapnem - - if(rotary_switch_state == "Automatic") - { - //prejs nodes - nacitame vsetky nody z pre danu liniu - for (let k in nodesData) { - //node:number|tbname:string|line:number|profile:string|processed:boolean - - //potrebujem nody k danej linii - if(record.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`); - } - } - } - - } - else - { - logger.debug("unable to process profile - rotary_switch_state is", rotary_switch_state); - } - - } - } - - relaysData = {...relaysDataTmp}; - - resolve("OK"); - - }); - }); - //resolve(stdout); - //reject(error); - - }) - } - - function reportOnlineNodeStatus(line, newRotarySwitchState) - { - //broadcast cas, o 1-2 sek neskor - status, brightness - - //Po zapnutí línie broadcastovo aktualizovať predtým čas. - - logger.debug("--->reportOnlineNodeStatus for line", line); - - //return; - - //run broadcast //Actual time (3x reportujeme -> prvy krat hned, potom po 20 sekundach pre istotu) - 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 - params.byte1 = hours;//h - params.byte2 = minutes;//m - params.byte3 = seconds;//s - params.byte4 = 0; - params.recipient = recipient; - params.register = 87;//Actual time - params.rw = 1;//write - - let timestampStart = priorityTypes.node_broadcast; - - //other values - params.type = "cmd"; - //params.tbname = tbname; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = addMinutesToTimestamp; - params.info = "run broadcast: Actual time"; - - tasks.push(params); - - params.timestamp = d.getTime() + 13000; - tasks.push(params); - - params.timestamp = d.getTime() + 14000; - tasks.push(params); - - if(newRotarySwitchState == 'Automatic') - { - - // we execute 3x the same command (1st after 30seconds, 2nd 31seconsd, 3rd 32seconds) - // cmd = WRITE: 255, 255, 255, 255, 255, 0, 8, 0, 0, 0, 17, 214, 34 - // 4bytes address, 1byte recipient, 2 register, 4bytes data, 2bytes crc - const timestamp = Date.now(); - - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - // params.tbname = ''; - params.address = 0xffffffff; //broadcast - params.register = 8; //register na casove profily pre nody - params.recipient = 2; //broadcast - params.rw = 1; //write - params.byte4 = 17; //decimal 17 - params.timestamp = timestamp + 13000; - params.info = 'znovuzapnutie profilov na svietidlach'; - tasks.push(params); - - params.timestamp = timestamp + 14000; - tasks.push(params); - - params.timestamp = timestamp + 15000; - tasks.push(params); - } - - if(newRotarySwitchState == 'Manual') - { - // we execute 3x the same command (1st after 30seconds, 2nd 31seconsd, 3rd 32seconds) - // cmd = WRITE: 255, 255, 255, 255, 255, 0, 8, 0, 0, 0, 0, 218, 226 - // 4bytes address, 1byte recipient, 2 register, 4bytes data, 2bytes crc - const timestamp = Date.now(); - - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - // params.tbname = ''; - params.address = 0xffffffff; //broadcast - params.register = 8; //register na casove profily pre nody - params.recipient = 2; //broadcast - params.rw = 1; //write - params.timestamp = timestamp + 13000; - params.info = 'vypnutie profilov na svietidlach'; - tasks.push(params); - - params.timestamp = timestamp + 14000; - tasks.push(params); - - params.timestamp = timestamp + 15000; - tasks.push(params); - - // after this 3 cmd, new cmds are executed: - // cmd = WRITE: 255, 255, 255, 255, 255, 0, 1, 0, 0, 0, 228, 144, 62 - - let newCmd = {...params}; - - newCmd.register = 1; - newCmd.byte4 = 228; // all nodes to 100% - newCmd.timestamp = timestamp + 17000; - tasks.push(newCmd); - - newCmd.timestamp = timestamp + 18000; - tasks.push(newCmd); - - newCmd.timestamp = timestamp + 19000; - tasks.push(newCmd); - } - - - let sec = 20; - 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) - { - let tbname = nodesData[k].tbname; - let node = nodesData[k].node; - - //prud, vykon - current, input power pre liniu pre vsetky nody - - //a pridame aj vyreportovanie dimmingu - { - let params = getParams(priorityTypes.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 = priorityTypes.high_priority; - params.info = 'read dimming / brightness (after set dimming from platform)'; - //params.debug = true; - - tasks.push(params); - } - - //Prúd - { - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - params.tbname = tbname; - params.address = node; - params.register = 75;//prud - params.recipient = 1;//slave - params.rw = 0;//read - params.timestamp = priorityTypes.high_priority; - params.info = 'read current (after set dimming from platform)'; - //params.debug = true; - - tasks.push(params); - } - - //výkon - { - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - params.tbname = tbname; - params.address = node; - params.register = 76;//výkon - params.recipient = 1;//slave - params.rw = 0;//read - params.timestamp = priorityTypes.high_priority; - params.info = 'read power (after set dimming from platform)'; - //params.debug = true; - - tasks.push(params); - } - - } - } - - },sec*1000); - - } - - 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; - - //logger.debug("node:", tbname); - - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - } - } - - //report OFFLINE for line - //relaysData[line].tbname; - - //values = {}; - //values["status"] = "OFFLINE";//prúd - } - - let now = new Date(); - console.log("CMD Manager installed", now.toLocaleString("sk-SK")); - - //To disable NTP time synchronization, type the following command at the terminal. - exec(`timedatectl set-ntp false`, (err, stdout, stderr) => { - if (err || stderr) { - console.error(err); - console.log(stderr); - - monitor.info("failed timedatectl set-ntp", err, stderr); - } - else - { - exec(`timedatectl set-timezone "Europe/Bratislava"`, (err, stdout, stderr) => { - if (err || stderr) { - console.error(err); - console.log(stderr); - - monitor.info("failed timedatectl set-timezone", err, stderr); - } - else - { - console.log("timedatectl set-timezone Europe/Bratislava"); - } - }); - } - }); - - function turnOnLine(line, info) - { - let obj = { - line: line, - command: "turnOn", - info: info - }; - - logger.debug("linia", line, obj); - - if(rotary_switch_state == 'Automatic') reportOnlineNodeStatus(undefined, 'Automatic'); - - instance.send(instanceSendTo.di_do_controller, obj); - } - - function turnOffLine(line, info) - { - let obj = { - line: line, - command: "turnOff", - info: info - }; - - logger.debug("linia", line, obj); - - instance.send(instanceSendTo.di_do_controller, obj); - } - - 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"; - else type = "UNKNOWN"; - - 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]) - { - //CRC_ERROR - message = "NOK"; - error = "CRC_ERROR c1"; - instance.send(instanceSendTo.debug, "CRC_ERROR c1"); - } - - if(c2 != bytes[10]) - { - //CRC_ERROR - message = "NOK"; - error = "CRC_ERROR c2"; - instance.send(instanceSendTo.debug, "CRC_ERROR c2"); - } - - //crc error - if(type != "RESPONSE") - { - instance.send(instanceSendTo.debug, bytes); - instance.send(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4]); - - //logger.debug(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4], bytes); - - error = "type is: " + type; - - message = "NOK"; - } - - return {message: message, type: type, error: error}; - } - - function buildTasks(params) - { - - //report FLOW.OMS_edge_fw_version as fw_version - //report date as startdate - - monitor.info("buildTasks - params", params); - //return; - - //https://service-prod01.worksys.io/gettime - - - let processLine;//defined line - - let init = false; - let processLineProfiles = true; - let processBroadcast = true; - let processNodes = true; - - if(params == undefined) - { - init = true; - tasks = []; - - logger.debug("-->buildTasks clear tasks"); - } - else - { - processLineProfiles = false; - processBroadcast = false; - processNodes = false; - - processLineProfiles = params.processLineProfiles; - processLine = params.line; - } - - //load profiles pre linie - //relaysData[ record["line"] ] - - let now = new Date(); - - if(processLineProfiles) - { - //process line profiles - let keys = Object.keys(relaysData); - for(let i = 0; i < keys.length; i++) - { - let line = keys[i];//line is turned off by default - let profilestr = relaysData[line].profile; - - //Reset linii - let resetLine = false; - if(FLOW.OMS_rvo_name == "Kovalov RVO 2" && line != '0' && init == true) resetLine = true; - - if(resetLine) - { - /* - - Takže v Koválove sú nastavené offesty pre dusk a dawn nasledovne: - - DUSK: offset +20 minút – teda napr. namiesto 17:00 bude 17:20 a reštart by sa robil v čase 17:19, teda o minútu skôr. Tak aby keď budeš robiť zapnutie o 17:20 tak na RVO1 sa svietidlá zapnú v rovnakom čase. Teda: vypnutie v čase DUSK_TIME + 19 minút, zapnutie v čase DUSK_TIME + 20 minút - DAWN: offset -30 minút – teda napr. namiesto 7:00 bude 6:30 a reštart by sa robil v čase 6:30, tak aby sa svietidlá zhasli rovnako s RVO1. Zapnutie by bolo 6:31. - - Teda: vypnutie v čase DAWN_TIME -30 minút, zapnutie v čase DAWN_TIME -29 minút - - Vždy po reštarte asi 30 sekúnd po zapnutí treba poslať aktuálny čas na nody. - */ - - //function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) - let duskOffset = 20; - let dawnOffset = -30; - let sunCalcResult = calculateDuskDown(new Date(), undefined, duskOffset, dawnOffset); - - console.log(sunCalcResult); - - //if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo - //if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo - - //DUSK - sumrak - { - - //vypneme liniu a o minitu zapneme - { - let value = 0;//vypneme liniu - let isDusk = true; - let isDawn = false; - - let dusk_time = sunCalcResult.dusk_time; - if(dusk_time < now.getTime()) dusk_time = dusk_time + 24*60*60*1000;//1den - - let params = getParams(priorityTypes.relay_profile); - params.type = "relay"; - params.line = line; - params.value = value; - params.tbname = relaysData[line].tbname; - params.timestamp = dusk_time; - params.duskOffset = duskOffset; - params.useProfile = false; - - //once a day - params.addMinutesToTimestamp = 24*60; - - //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; - - if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; - else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; - - params.debug = true; - - //turn on/off line - tasks.push(params); - - console.log(params); - } - - //a o minutu zapneme - { - let value = 1;//zapneme liniu - let isDusk = true; - let isDawn = false; - - let dusk_time = sunCalcResult.dusk_time + 60*1000;//o minutu neskor po vypnuti zapneme - if(dusk_time < now.getTime()) dusk_time = dusk_time + 24*60*60*1000;//1den - - let params = getParams(priorityTypes.relay_profile); - params.type = "relay"; - params.line = line; - params.value = value; - params.tbname = relaysData[line].tbname; - params.timestamp = dusk_time; - params.duskOffset = duskOffset + 1; - params.useProfile = false; - - //once a day - params.addMinutesToTimestamp = 24*60; - - //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; - - if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; - else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; - - params.debug = true; - - //turn on/off line - tasks.push(params); - - console.log(params); - } - - - } - - //DAWN - vychod - { - //vypneme liniu a o minitu zapneme - { - let value = 0;//vypneme liniu - let isDusk = false; - let isDawn = true; - - let dawn_time = sunCalcResult.dawn_time; - if(dawn_time < now.getTime()) dawn_time = dawn_time + 24*60*60*1000;//1den - - let params = getParams(priorityTypes.relay_profile); - params.type = "relay"; - params.line = line; - params.value = value; - params.tbname = relaysData[line].tbname; - params.timestamp = dawn_time; - - params.dawnOffset = dawnOffset; - params.useProfile = false; - - //once a day - params.addMinutesToTimestamp = 24*60; - - //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; - - if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; - else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; - - params.debug = true; - - //turn on/off line - tasks.push(params); - - console.log(params); - } - - //a o minitu zapneme - { - let value = 1;//vypneme liniu - let isDusk = false; - let isDawn = true; - - let dawn_time = sunCalcResult.dawn_time + 1000*60;//o minutu neskor po vypnuti zapneme - if(dawn_time < now.getTime()) dawn_time = dawn_time + 24*60*60*1000;//1den - - let params = getParams(priorityTypes.relay_profile); - params.type = "relay"; - params.line = line; - params.value = value; - params.tbname = relaysData[line].tbname; - params.timestamp = dawn_time; - - params.dawnOffset = dawnOffset + 1; - params.useProfile = false; - - //once a day - params.addMinutesToTimestamp = 24*60; - - //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; - - if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; - else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; - - params.debug = true; - - //turn on/off line - tasks.push(params); - - console.log(params); - } - - - } - - //console.log("-------------------------Kovalov RVO 2----"); - } - - if(processLine != undefined) - { - if(processLine != line) continue; - } - - try{ - - if(profilestr === "") throw ("profile is not defined"); - let profile = JSON.parse(profilestr); - if(Object.keys(profile).length === 0) throw ("profile is not defined"); - - 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; - - monitor.info("buildTasks: time_points", time_points); - - let currentValue = 0; - if(time_points.length > 0) currentValue = time_points[ time_points.length - 1].value; - - //create task for tun on + turn off, calculate dusk/down - if(profile.astro_clock == true) - { - //let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"}); - let sunCalcResult = calculateDuskDown(new Date(), line); - - monitor.info("dusk and dawn sunCalcResult", line, sunCalcResult); - - //add to timpoints - if(profile.dawn_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dawn"], "value": 1, "isDawn": true} ); - if(profile.dusk_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dusk"], "value": 0, "isDusk": true} ); - - //aby nam to neostalo svietit - if(profile.dawn_lux_sensor == true) - { - //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window - 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); - - let strDate = ad.getHours() + ":" + ad.getMinutes(); - - time_points.push( {"value": 0, "start_time": strDate} ); - } - - if(profile.dusk_lux_sensor == true) - { - //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window - let [ahours, aminutes, aseconds] = sunCalcResult["dusk"].split(':'); - - let ad = new Date(); - ad.setHours( parseInt(ahours) ); - ad.setMinutes( parseInt(aminutes) + profile.dawn_lux_sensor_time_window ); - ad.setSeconds(0); - - let strDate = ad.getHours() + ":" + ad.getMinutes(); - - time_points.push( {"value": 1, "start_time": strDate} ); - } - } - - //sort time_points - 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(); - }); - - monitor.info("-->comming events turn on/off lines:"); - for(let t = 0; t < time_points.length; t++) - { - - let start_time = new Date(); - - let isDusk = false; - let isDawn = false; - if(time_points[t].hasOwnProperty("isDusk")) isDusk = time_points[t].isDusk; - if(time_points[t].hasOwnProperty("isDawn")) isDawn = time_points[t].isDawn; - - if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo - if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo - - if(time_points[t].hasOwnProperty("start_time")) - { - let [hours, minutes, seconds] = time_points[t].start_time.split(':'); - - start_time.setHours( parseInt(hours) ); - start_time.setMinutes( parseInt(minutes) ); - start_time.setSeconds(0); - } - - //task is the past - if(now.getTime() > start_time.getTime()) - { - currentValue = time_points[t].value; - - //je v minulosti, pridame 24h - start_time.setDate(start_time.getDate() + 1); - } - - let params = getParams(priorityTypes.relay_profile); - params.type = "relay"; - params.line = line; - params.value = time_points[t].value; - params.tbname = relaysData[line].tbname; - params.timestamp = start_time.getTime(); - - params.addMinutesToTimestamp = 0; - - //once a day - if(!isDusk && !isDawn) params.addMinutesToTimestamp = 24*60; - - //inak sa cas vypocita dynamicky - - //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; - - //if(profile.astro_clock == true && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) - - if(params.value == 0) - { - params.info = "turn off line: " + line; - if(isDusk) params.info = "dusk: turn off line: " + line; - if(isDawn) params.info = "dawn: turn off line: " + line; - } - else if(params.value == 1) - { - params.info = "turn on line: " + line; - if(isDusk) params.info = "dusk: turn on line: " + line; - if(isDawn) params.info = "dawn: turn on line: " + line; - } - - params.debug = true; - - //turn on/off line - tasks.push(params); - - monitor.info(params.info, start_time); - - } - - monitor.info("-->time_points final", line, time_points); - - //ensure to turn on/off according to calculated value - let params = getParams(priorityTypes.terminal); - params.type = "relay"; - params.line = parseInt(line); - params.tbname = relaysData[line].tbname; - params.value = currentValue; - params.isDusk = false; - params.isDawn = false; - - params.timestamp = priorityTypes.terminal; - params.addMinutesToTimestamp = 0; - params.debug = true; - - //logger.debug(now.toLocaleString("sk-SK")); - 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; - - tasks.push(params); - - - } catch (error) { - if(profilestr !=="" ) - { - //errLogger.error(profilestr, error); - errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error"); - } - } - - } - - //logger.debug("tasks:"); - //logger.debug(tasks); - } - - - //PROCESS DEFAULT BROADCASTS - - //RPC pre nody / broadcast - //Time of dusk, Time of dawn - //Actual Time - - if(processBroadcast) - { - let addMinutesToTimestamp = 5; - - { - //run broadcast Time of dusk - addMinutesToTimestamp = 60*5; - - let params = getParams(priorityTypes.node_broadcast); - - let recipient = 2;//2 broadcast, address = 0 - let address = 0;//0 - if(recipient === 2) - { - address = 0xffffffff;//Broadcast - } - - let sunCalcResult = calculateDuskDown(); - let dusk_hours = sunCalcResult["dusk_hours"]; - let dusk_minutes = sunCalcResult["dusk_minutes"]; - - params.address = address;//broadcast - params.byte1 = dusk_hours;//h - params.byte2 = dusk_minutes;//m - params.byte3 = 0;//s - params.byte4 = 0; - params.recipient = recipient; - params.register = 6;//Time of dusk - Reg 6 - params.rw = 1;//write - - let timestampStart = priorityTypes.node_broadcast; - - //other values - params.type = "cmd"; - //params.tbname = tbname; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = addMinutesToTimestamp; - params.info = "run broadcast Time of dusk"; - - tasks.push(params); - - } - - { - - //run broadcast Time of dawn - addMinutesToTimestamp = 60*5; - - let params = getParams(priorityTypes.node_broadcast); - - let recipient = 2;//2 broadcast, address = 0 - let address = 0;//0 - if(recipient === 2) - { - address = 0xffffffff;//Broadcast - } - - let sunCalcResult = calculateDuskDown(); - let dawn_hours = sunCalcResult["dawn_hours"]; - let dawn_minutes = sunCalcResult["dawn_minutes"]; - - params.address = address;//broadcast - params.byte1 = dawn_hours;//h - params.byte2 = dawn_minutes;//m - params.byte3 = 0;//s - params.byte4 = 0; - params.recipient = recipient; - params.register = 7;//Time of dawn - Reg 6 - params.rw = 1;//write - - let timestampStart = priorityTypes.node_broadcast; - - //other values - params.type = "cmd"; - //params.tbname = tbname; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = addMinutesToTimestamp; - params.info = "run broadcast Time of dawn"; - - tasks.push(params); - } - - - { - //run broadcast //Actual time - addMinutesToTimestamp = 5; - - let params = getParams(priorityTypes.node_broadcast); - - 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 - params.byte1 = hours;//h - params.byte2 = minutes;//m - params.byte3 = seconds;//s - params.byte4 = 0; - params.recipient = recipient; - params.register = 87;//Actual time - params.rw = 1;//write - - let timestampStart = priorityTypes.node_broadcast; - - //other values - params.type = "cmd"; - //params.tbname = tbname; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = addMinutesToTimestamp; - params.info = "run broadcast: Actual time"; - - tasks.push(params); - - } - - { - //run broadcast Actual Lux level from cabinet - - //Do tohto registra posiela riadiaca jednotka hodnotu intenzity osvetlenia ktorú meria jej senzor pre potreby riadenia časov súmraku resp. úsvitu podľa intenzity osvetlenia. - //Byty 0 (LSB) a 1 obsahujú 16 bitový integer s luxami. - - let params = getParams(priorityTypes.node_broadcast); - - addMinutesToTimestamp = 15; - - let recipient = 2;//2 broadcast, address = 0 - let address = 0;//0 - if(recipient === 2) - { - address = 0xffffffff;//Broadcast - } - - //TODO - //16 bitový integer s luxami - params.byte3 = lux_sensor; - params.byte4 = lux_sensor; - params.timestamp = priorityTypes.node_broadcast; - params.addMinutesToTimestamp = addMinutesToTimestamp; - params.info = "run broadcast: Actual Lux level from cabinet"; - params.register = 95;//Actual Lux level from cabinet - params.rw = 1;//write - - } - } - - //process nodes & tasks - //reportovanie pre platformu - 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++) - { - register = listOfCommands[i]; - - let params = getParams(priorityTypes.node_cmd); - - //core rpc values - params.address = address; - params.byte1 = 0; - params.byte2 = 0; - params.byte3 = 0; - params.byte4 = 0; - params.recipient = 1; - params.register = register; - params.rw = 0; - - let addMinutesToTimestamp = priorities[register]; - - let timestampStart = priorityTypes.node_cmd; //run imediatelly in function runTasks - 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; - - - //Priebežne (raz za cca 5 minút) je potrebné vyčítať z Master nodu verziu jeho FW. - //Jedná sa o register 10. Rovnaká interpretácia ako pri FW verzii nodu. - //Adresa mastera je 0. V prípade že kedykoľvek nastane situácia že Master Node neodpovedá (napríklad pri vyčítaní telemetrie z nodu nevráti žiadne dáta), - //tak treba vyreportovať string "NOK". - { - let params = getParams(priorityTypes.fw_detection); - params.type = "cmd"; - params.register = 4; - params.address = 0; - - let timestampStart = priorityTypes.fw_detection; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = 5; - params.tbname = FLOW.OMS_edgeName; - params.info = "Master node FW verzia"; - //params.debug = true; - - //this will set FLOW.OMS_masterNodeIsResponding - - tasks.push(params); - } - - //kazdu hodinu skontrolovat nastavenie profilov - { - //get exact datetime from services - //https://service-prod01.worksys.io/gettime - - let params = getParams(priorityTypes.fw_detection); - params.type = "process_profiles"; - - let timestampStart = priorityTypes.relay_profile; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = 60;//60 = every hour - params.info = "detekcia nespracovaných profilov linie a nodov"; - //params.debug = true; - - tasks.push(params); - } - - { - //get exact datetime from services - //https://service-prod01.worksys.io/gettime - //https://service-prod01.worksys.io/#main - //https://sa-prod01.worksys.io/ - //https://code-prod01.worksys.io/ - - let params = getParams(priorityTypes.fw_detection); - params.type = "ntp-gettime"; - - let timestampStart = priorityTypes.fw_detection; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = 60;//every hour - params.info = "https://service-prod01.worksys.io/gettime"; - //params.debug = true; - - //this will set FLOW.OMS_masterNodeIsResponding - - tasks.push(params); - } - - { - //edge_date_time - - let params = getParams(priorityTypes.node_cmd); - params.type = "edge_date_time"; - - let timestampStart = priorityTypes.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(priorityTypes.node_cmd); - params.type = "number_of_luminaires"; - - let timestampStart = priorityTypes.node_cmd + 1; - params.timestamp = timestampStart; - params.addMinutesToTimestamp = 1; - params.tbname = FLOW.OMS_edgeName; - params.info = "reportovanie number_of_luminaires"; - - tasks.push(params); - } - - monitor.info("tasks created:", tasks.length); - } - - function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) - { - //let dusk_hours = sunCalcResult["dusk_hours"]; - //let dusk_minutes = sunCalcResult["dusk_minutes"]; - - let duskTimeStamp; - let downTimeStamp; - - //prejedme si line s profilom, kde mame "astro_clock": true - - /* - "dawn_lux_sensor": true, - "dusk_lux_sensor": true, - "dawn_lux_sensor_value": 5, - "dusk_lux_sensor_value": 5, - "dawn_astro_clock_offset": 0, - "dusk_astro_clock_offset": 10, - "dawn_lux_sensor_time_window": 30, - "dusk_lux_sensor_time_window": 30, - "dawn_astro_clock_time_window": 60, - "dusk_astro_clock_time_window": 60 - */ - - //ak sme pred/po vychode a lux value <= lux_sensor_value, liniu zapneme - - //ak sme pred/po zapade a lux_value <= lux_sensor_value, liniu zapneme - - let now = new Date(); - let currentTimestamp = now.getTime(); - - let keys = Object.keys(relaysData); - for(let i = 0; i < keys.length; i++) - { - let line = keys[i];//line is turned off by default - let profilestr = relaysData[line].profile; - - try{ - - let profile = JSON.parse(profilestr); - if(Object.keys(profile).length === 0) throw ("profile is not defined"); - - if(profile.astro_clock == true) - { - let sunCalcResult = calculateDuskDown(date, line); - - //dawn: usvit/vychod - lux je nad hranicou - vypnem - //dusk: zapad pod hranicou - zapnem - - //"dawn_lux_sensor_time_window": 30, - //"dusk_lux_sensor_time_window": 30, - - //vychod - if(profile.dawn_lux_sensor == true) - { - let lux_sensor_time_window1 = sunCalcResult.dawn_time - parseInt( profile.dawn_lux_sensor_time_window ); - let lux_sensor_time_window2 = sunCalcResult.dawn_time + parseInt( profile.dawn_lux_sensor_time_window ); - - if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) - { - //dawn: usvit/vychod - lux je nad hranicou - vypnem - if(lux_sensor_value > profile.dawn_lux_sensor_value) - { - //vypnem - turnOffLine(line, "profile: dawn - turnOff line according to lux sensor"); - } - else - { - //zapnem - turnOnLine(line, "profile: dawn - turnOn line according to lux sensor"); - } - - } - - //ak sme po vychode - if(currentTimestamp > lux_sensor_time_window2) - { - //vypneme - //urobime jednorazovy prikaz - } - } - - //zapad - if(profile.dusk_lux_sensor == true) - { - let lux_sensor_time_window1 = sunCalcResult.dusk_time - parseInt( profile.dusk_lux_sensor_time_window ); - let lux_sensor_time_window2 = sunCalcResult.dusk_time + parseInt( profile.dusk_lux_sensor_time_window ); - - if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) - { - //dusk: zapad pod hranicou - zapnem - if(lux_sensor_value < profile.dusk_lux_sensor_value) - { - //zapnem - turnOnLine(line, "profile: dusk - turnOff line according to lux sensor"); - } - else - { - //vypnem - turnOffLine(line, "profile: dusk - turnOff line according to lux sensor"); - } - - } - } - - - } - - } catch (error) { - //if(profilestr !=="" ) logger.debug(profilestr, error); - } - } - } - - let sunCalcResult = calculateDuskDown(); - - let reportDuskDawn = { - dusk_time: sunCalcResult.dusk_time, - dawn_time: sunCalcResult.dawn_time, - dusk_time_reported: undefined, - dawn_time_reported: undefined - }; - - async function upateNodeStatus(node, status) - { - //MASTER - if(node == 0) return; - - let nodeObj = nodesData[node]; - if(nodeObj == undefined) return; - - if(status) - { - cmdNOKNodeCounter[node] = 0; - } - 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; - }); - }); - } - } - - - async function runTasks() { - - clearInterval(interval); - - let currentTimestamp = Date.now(); - - //report dusk, dawn--------------------------------- - if(reportDuskDawn.dusk_time < currentTimestamp) - { - //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund - 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"]}, "", instanceSendTo.tb, instance); - reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time; - } - } - - var nextDay = new Date(); - nextDay.setDate(nextDay.getDate() + 1); - - sunCalcResult = calculateDuskDown(nextDay); - reportDuskDawn.dusk_time = sunCalcResult.dusk_time; - } - - if(reportDuskDawn.dawn_time < currentTimestamp) - { - //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund - if( (currentTimestamp - reportDuskDawn.dusk_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"]}, "", instanceSendTo.tb, instance); - reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time; - } - } - - var nextDay = new Date(); - nextDay.setDate(nextDay.getDate() + 1); - - sunCalcResult = calculateDuskDown(nextDay); - reportDuskDawn.dawn_time = sunCalcResult.dawn_time; - - } - //-------------------------------------------------------- - - //sort tasks - //tasks.sort((a,b) => a.timestamp - b.timestamp ); - - 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 ) - { - instance.send(instanceSendTo.debug, "no tasks created"); - interval = setInterval(runTasks, longInterval); - - return; - } - - if(!rsPort.isOpen) - { - instance.send(instanceSendTo.debug, "!rsPort.isOpen"); - //await rsPort.open(); - - //continue - } - - let currentTask = tasks[0]; - - if(currentTask.debug) - { - //logger.debug("--->task to process", currentTask); - } - - if(currentTask.timestamp <= currentTimestamp) - { - let params = {...tasks[0]}; - - if(FLOW.OMS_maintenance_mode) - { - - //allow terminal commands - if(params.type == "cmd-terminal"); - else - { - interval = setInterval(runTasks, longInterval); - return; - } - } - - let type = params.type; - let tbname = params.tbname; - let nodeKey = params.address; - - let useProfile = params.useProfile; - if(useProfile === undefined) useProfile = true; - let duskOffset = params.duskOffset; - let dawnOffset = params.dawnOffset; - - let line = null; - //rpc related - if(nodesData[nodeKey] !== undefined) line = nodesData[nodeKey].line; - if(params.line !== undefined) line = params.line; - - let repeatTask = false; - if(params.addMinutesToTimestamp > 0) repeatTask = true; - if(params.isDawn || params.isDusk) repeatTask = true; - - if(repeatTask) - { - if(type == "cmd") - { - //set next start time automatically - tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - } - } - else - { - //terminal data... - 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(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - - interval = setInterval(runTasks, shortIterval); - - return; - } - } - - if(type == "ntp-gettime") - { - - RESTBuilder.make(function(builder) { - - if(!builder) return; - - builder.method('GET'); - //FLOW.OMS_edge_fw_version - builder.url('http://192.168.252.2:8004/gettime?projects_id=1'); - - builder.callback(function(err, response, output) { - - if (err) { - console.log(err); - return; - } - - instance.send(instanceSendTo.debug, "RESTBuilder response"); - const res = output.response; - - try{ - - const obj = JSON.parse(res); - let d = new Date(obj.date); - - const now = new Date(); - - //offset in minutes - convertUTCDateToLocalDate - let diffInMinutes = now.getTimezoneOffset(); - //d.setMinutes( d.getMinutes() + diffInMinutes ); - - //let converted = convertUTCDateToLocalDate(d); - - console.log("---->TimezoneOffset", diffInMinutes); - - if(d instanceof Date) - { - console.log("current js date:", d, d.getHours()); - - let year = d.getFullYear(); - let month = addZeroBefore(d.getMonth() + 1); - let day = addZeroBefore(d.getDate()); - - //-2 hodiny!!!! - let hours = addZeroBefore( d.getHours() ); - let minutes = addZeroBefore(d.getMinutes() ); - let seconds = addZeroBefore(d.getSeconds()); - - let timestamp = `${year}${month}${day} ${hours}:${minutes}:${seconds}`; - let dstr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; - - logger.debug("--->RESTBuilder response", res, timestamp, dstr); - - //TODO - poslat notifikaciu a nastav hw cas - //timedatectl set-timezone "Europe/Bratislava" - //hwclock --set --date="2021-08-24 15:02:00" --localtime - - //https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/ - - - //timedatectl set-time "2022-04-27 09:13:00" - { - - let year = d.getUTCFullYear(); - let month = addZeroBefore(d.getUTCMonth() + 1); - let day = addZeroBefore(d.getUTCDate()); - - let hours = addZeroBefore( d.getUTCHours() ); - let minutes = addZeroBefore(d.getUTCMinutes() ); - let seconds = addZeroBefore(d.getUTCSeconds()); - - let UTCstr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; - - exec(`timedatectl set-time "${UTCstr}"`, (err, stdout, stderr) => { - if (err || stderr) { - console.error(err); - console.log(stderr); - console.log(UTCstr); - - monitor.info("failed timedatectl set-time", err, stderr); - } - else - { - console.log(`UTC: timedatectl set-time "${UTCstr}"`); - } - - }); - } - - //RTC time - hardware time - ak je RTC in local TZ: yes - nastavime UTC preratany podla timezone - exec(`hwclock --set --date="${dstr}" --localtime`, (err, stdout, stderr) => { - if (err || stderr) { - console.error(err); - console.log(stderr); - - monitor.info("failed to set date", dstr, res, err, stderr); - - } else { - console.log(stdout); - console.log(`Successfully set the system's datetime - ${dstr}`); - - const now = new Date(); - console.log(now); - - } - }); - - //detect Read-only file system - - ///dev/mmcblk0p2 on / type ext3 (rw,noatime,nodiratime,errors=remount-ro,commit=100,data=ordered) - (if ro = Read-only file system) - - //egrep " ro,|,ro " /proc/mounts - //mount - - exec(`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); - } - - } - }); - - /* - //povodna verzia - exec(`sudo /bin/date --set="${timestamp}"`, (err, stdout, stderr) => { - if (err || stderr) { - console.error(err); - console.log(stderr); - - monitor.info("failed to set date", d, res, err, stderr); - - } else { - console.log(stdout); - console.log(`Successfully set the system's datetime to ${stdout}`); - - const now = new Date(); - console.log(now); - - } - }); - */ - - } - - - } catch (error) { - logger.debug("--->ntp-gettime", error, res); - } - - - }); - }); - - tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - - interval = setInterval(runTasks, shortIterval); - - return; - } - - //kontrola nespracovanych profilov nodov - 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(); - - interval = setInterval(runTasks, shortIterval); - return; - } - - if(type == "edge_date_time") - { - - //var d = new Date(); - //let hours = addZeroBefore(d.getHours()); - //let minutes = addZeroBefore(d.getMinutes()); - //let seconds = addZeroBefore(d.getSeconds()); - //let values = {"edge_date_time": `${hours}:${minutes}:${seconds}`}; - - let values = {"edge_date_time": Date.now()}; - - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - - interval = setInterval(runTasks, shortIterval); - - return; - } - - //relay - if(type == "relay") - { - - //ak je dusk, alebo dawn, vypocitame si dynamicky nove values - if(params.isDawn || params.isDusk) - { - let date = new Date(); - date.setDate(date.getDate() + 1);//next day - - let sunCalcResult; - if(useProfile) sunCalcResult = calculateDuskDown(date, params.line); - else - { - //do not use profile, line is there for undefined - sunCalcResult = calculateDuskDown(date, undefined, duskOffset, dawnOffset); - } - - if(params.isDawn) - { - tasks[0].timestamp = sunCalcResult.dawn_time; - } - - if(params.isDusk) - { - tasks[0].timestamp = sunCalcResult.dusk_time; - } - } - else - { - if(tasks[0].addMinutesToTimestamp == 0);// tasks.shift(); - else tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - } - - let info; - if(useProfile) info = "aplikovaný bod profilu"; - else info = params.info; - - let message = ""; - if(params.value == 1) - { - turnOnLine(params.line, info); - message = "on"; - } - else if(params.value == 0) - { - turnOffLine(params.line, info); - message = "off"; - } - - //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", instanceSendTo.tb, instance, null ); - if(useProfile) sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", instanceSendTo.tb, instance ); - - interval = setInterval(runTasks, shortIterval); - return; - } - - //zhodeny hlavny istic - let disconnected = false; - //if(rotary_switch_state == "Off") disconnected = true; - - //state_of_breaker[line] - alebo istic linie - if(state_of_breaker.hasOwnProperty(line)) - { - //if(state_of_breaker[line] == "Off") disconnected = true; - } - - //toto sa reportuje po prijati dat z di_do_controlera - 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[tbname]) - { - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - } - - interval = setInterval(runTasks, shortIterval); - - return; - } - - disconnectedReport[tbname] = false; - - //high_priority - if(!FLOW.OMS_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) - { - interval = setInterval(runTasks, longInterval); - return; - } - - } - - let relayStatus = 1; - if(relaysData[line] != undefined) - { - relayStatus = relaysData[line].contactor; - } - - if(line == 0) relayStatus = 0; - if(params.type == "cmd-terminal") relayStatus = 1; - - //check if rotary_switch_state == "Off" - - if(relayStatus == 0) - { - //console.log("------------------------------------relayStatus", relayStatus, line); - let values = {"status": "OFFLINE"}; - - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - - interval = setInterval(runTasks, shortIterval); - - return; - } - - if(!rsPort.isOpen) - { - interval = setInterval(runTasks, longInterval); - return; - } - - //RE-CALCULATE VALUES - //set actual time for broadcast - if(params.register == 87 && params.recipient === 2) - { - var d = new Date(); - let hours = d.getHours(); - let minutes = d.getMinutes(); - let seconds = d.getSeconds(); - - params.byte1 = hours;//h - params.byte2 = minutes;//m - params.byte3 = seconds;//s - params.byte4 = 0; - } - - //set dusk/down for broadcast - - //Time of dusk - if(params.register == 6 && params.recipient === 2) - { - let sunCalcResult = calculateDuskDown(); - 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 - params.byte4 = 0; - - //TODO astrohodiny - let dusk = "Time of dusk: " + sunCalcResult["dusk"]; - //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", instanceSendTo.tb, instance, null ); - } - - //Time of dawn - if(params.register == 7 && params.recipient === 2) - { - let sunCalcResult = calculateDuskDown(); - 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 - params.byte4 = 0; - - //TODO astrohodiny - let dawn = "Time of dawn: " + sunCalcResult["dawn"]; - //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", instanceSendTo.tb, instance, null ); - } - //----------------------- - - - let register = params.register; - instance.send(instanceSendTo.debug, "address: " + params.address + " register:" + params.register + "type: " + params.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; - - //if broadcast WRITE - do not read - //if(params.recipient == 2) readBytes = 0; - - //WRITE + BROADCAST = readBytes = 0; - if(params.rw == 1 && params.recipient == 2) readBytes = 0; - - if(params.hasOwnProperty("debug")) - { - //console.log("--->readBytes", readBytes, params); - } - - await writeData(rsPort, resp, readBytes).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; - - //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK - - if(params.debug != "generated cmd") - { - //debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug, params); - } - - if(params.hasOwnProperty("debug")) - { - if(params.debug) - { - console.log("detected response:", result); - - logger.debug("writeData: done " + type + " 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); - - let tbname = params.tbname; - - let saveToTb = true; - if(tbname == null || tbname == undefined || tbname == "") saveToTb = false; - //-- - - //CMD FINISHED - if(message == "OK") - { - - upateNodeStatus(params.address, 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) { - - builder.callback(function(err, response) { - - sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "dimming_profile_was_successfully_received_by_node", {node: params.address}, "", instanceSendTo.tb, instance ); - - logger.debug( "--> profil úspešne odoslaný na node č. " + params.address); - nodesData[params.address].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.register == 0) values["status"] = message; - - //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", "", instanceSendTo.tb, instance, "rvo_status" ); - //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", instanceSendTo.tb, instance, "rvo_status" ); - sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_responding_again", {}, "", instanceSendTo.tb, instance, "rvo_status" ); - FLOW.OMS_masterNodeIsResponding = true; - } - - //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, instanceSendTo.tb, instance, null ); - sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "command_was_sent_from_terminal_interface", {}, params, instanceSendTo.tb, instance ); - } - - if(params.debug) - { - logger.debug("saveToTb", saveToTb, tbname, values); - } - - if(saveToTb) - { - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - - } - 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(instanceSendTo.http_response, params.refFlowdata); - - let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; - refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, refFlowdata); - - } - else - { - console.log("params.refFlowdataKey is undefined", params); - } - } - - } - - } - else - { - - upateNodeStatus(params.address, false); - - 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(instanceSendTo.http_response, params.refFlowdata); - - let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; - if(refFlowdata !== undefined) - { - refFlowdata.data = responseObj; - instance.send(instanceSendTo.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(instanceSendTo.http_response, params.refFlowdata); - - } - } - */ - - if(params.address == 0) - { - //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", instanceSendTo.tb, instance, "rvo_status"); - sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", instanceSendTo.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, "", instanceSendTo.tb, instance, null ); - sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.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(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - } - - //instance.send(instanceSendTo.debug, result); - - if(params.hasOwnProperty("debug")) - { - if(params.debug) - { - logger.debug("writeData err: ", error, result, params); - } - } - - //logger.debug(error, result, params); - } - - }).catch(function (reason) { - - console.log("writeData catch exception", reason); - logger.debug(currentTask); - - if(params.refFlowdataKey != undefined) - { - - 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(instanceSendTo.http_response, params.refFlowdata); - - let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; - if(refFlowdata !== undefined) - { - refFlowdata.data = responseObj; - instance.send(instanceSendTo.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(instanceSendTo.http_response, params.refFlowdata); - - //refFlowdata = undefined; - } - } - */ - - 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", "", instanceSendTo.tb, instance, "rvo_status"); - sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", instanceSendTo.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", "", instanceSendTo.tb, instance, null ); - sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.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(instanceSendTo.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(instanceSendTo.tb, dataToTb); - } - */ - - instance.send(instanceSendTo.debug, reason); - }); - - } - else - { - if(currentTask.debug) - { - //currentTask.timestamp <= currentTimestamp - logger.debug("currentTask is not processed - task is in the future", currentTask); - } - - interval = setInterval(runTasks, longInterval); - return; - } - - //console.log("----->runTasks - setInterval", new Date()); - interval = setInterval(runTasks, shortIterval); - } - - //! 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 = "ttymxc4"; - if(FLOW.OMS_serial_port == undefined) FLOW.OMS_serial_port = "ttymxc4"; - if(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); - - rsPort.on('open', async function() { - - logger.debug("CMD manager - rsPort opened sucess"); - - await loadRelaysData(); - - 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(instanceSendTo.debug, "RPC runSyncExec - Promise Resolved:" + status); - - logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status); - - //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(instanceSendTo.infoSender, dataToInfoSender); - - logger.debug(0, "---------------------------->START message send to service", dataToInfoSender); - - //---- - - nodesData = {}; - - dbNodes.find().make(function(builder) { - builder.callback(function(err, response) { - - for(let i = 0; i < response.length; i++) - { - let node = response[i]; - let key = node["node"]; - - nodesData[ key ] = node; - } - - //buildTasks(); - //interval = setInterval(runTasks, longInterval); - - }); - }); - - }).catch(function (reason) { - instance.send(instanceSendTo.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason); - }); - - }); - - 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); - - instance.send(instanceSendTo.debug, err.message); - }); - - rsPort.on("close", () => { - rsPort.close(); - }); - - //loadRelaysData(); - rsPort.open(); - - instance.on("close", () => { - clearInterval(interval); - rsPort.close(); - }); - - //onData - instance.on("data", async function(flowdata) { - //instance.on("data", (data) => { - - //instance.send(instanceSendTo.debug, "on Data"); - //instance.send(instanceSendTo.debug, flowdata); - - //logger.debug(flowdata.data); - - //just testing functions - if(flowdata.data == "open") - { - if(!rsPort.isOpen) rsPort.open(); - return; - } - else if(flowdata.data == "close") - { - rsPort.close(); - return; - } - else if(flowdata.data == "clean") - { - tasks = []; - return; - } - else if(flowdata.data == "buildtasks") - { - //build & run - return; - } - else if(flowdata.data == "run") - { - //durations = []; - - if(tasks.length == 0) - { - - buildTasks(); - - if(rsPort.isOpen) - { - interval = setInterval(runTasks, 100); - } - else - { - instance.send(instanceSendTo.debug, "port is not opened!!!"); - } - } - } - else - { - //terminal data - object - //logger.debug("flowdata", flowdata.data); - - if(typeof flowdata.data === 'object') - { - //logger.debug("dido", flowdata.data); - if(flowdata.data.hasOwnProperty("sender")) - { - //data from di_do_controller - if(flowdata.data.sender == "di_do_controller") - { - - if(flowdata.data.hasOwnProperty("cmd")) - { - let cmd = flowdata.data.cmd; - - - if(cmd == "buildTasks") - { - clearInterval(interval); - - logger.debug("-->CMD MANAGER - BUILD TASKS"); - buildTasks(); - - //logger.debug("tasks:"); - //logger.debug(tasks); - - logger.debug("-->CMD MANAGER - RUN TASKS"); - interval = setInterval(runTasks, longInterval); - } - else if(cmd == "reload_relays") - { - await loadRelaysData(flowdata.data.line); - - if(flowdata.data.dataChanged) - { - if(!flowdata.data.value) - { - reportOfflineNodeStatus(flowdata.data.line); - } - else - { - reportOnlineNodeStatus(flowdata.data.line); - } - } - - } - else if(cmd == "rotary_switch_state") - { - //state was changed - if(rotary_switch_state != flowdata.data.value) - { - - if(flowdata.data.value == "Off") - { - //vyreportovat vsetky svietdla - reportOfflineNodeStatus(); - } - else reportOnlineNodeStatus(undefined, flowdata.data.value); - - } - - rotary_switch_state = flowdata.data.value; - - } - else if(cmd == "lux_sensor") - { - lux_sensor = parseInt(flowdata.data.value); - - //process profiles - turnOnOffLinesAccordingToLuxSensor(lux_sensor); - } - 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; - - 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(dataChanged) { - - 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}, "", instanceSendTo.tb, instance, "circuit_breaker"); - else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", {line: line}, "", instanceSendTo.tb, instance, "circuit_breaker"); - - //report status liniu - let values = { - "status": status - }; - - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - //instance.send(instanceSendTo.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - - //current value - if(value == "Off") - { - //vyreportovat vsetky svietdla na linii - reportOfflineNodeStatus(line); - } - else reportOnlineNodeStatus(line); - } - - } - } - else{ - logger.debug("undefined cmd", cmd); - } - } - } - - return; - } - - //data from worksys - if(flowdata.data.hasOwnProperty("topic")) - { - - let data = flowdata.data.content.data; - - let command = data.params.command; - let method = data.method; - let profile = data.params.payload; - if(profile == undefined) profile = ""; - let entity = data.params.entities[0]; - let entity_type = entity.entity_type; - let tbname = entity.tb_name; - - instance.send(instanceSendTo.debug, flowdata.data); - logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method); - logger.debug("----------------------------"); - - if(entity_type == "street_luminaire") - { - if(method == "set_command") - { - - //let command = data.params.command; - let value = data.params.payload.value; - - if(command == "dimming") - { - - let nodeWasFound = false; - let keys = Object.keys(nodesData); - - //logger.debug("-----", keys); - - 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(priorityTypes.high_priority); - - 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 = priorityTypes.high_priority; - params.info = 'set dimming from platform'; - //params.debug = true; - - //ak linia je - - //debug(params); - logger.debug("dimming", params); - - tasks.push(params); - - setTimeout(function(){ - - //spustime o 4 sekundy neskor, s prioritou priorityTypes.high_priority - //a pridame aj vyreportovanie dimmingu - { - let params = getParams(priorityTypes.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 = priorityTypes.high_priority; - params.info = 'read dimming (after set dimming from platform)'; - params.debug = true; - - tasks.push(params); - } - - //pridame aj vyreportovanie - vykon - { - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - params.tbname = tbname; - params.address = node; - params.register = 76; - params.recipient = 1;//slave - params.rw = 0;//read - params.timestamp = priorityTypes.high_priority; - params.info = 'read Input Power (after set dimming from platform)'; - params.debug = true; - - tasks.push(params); - } - - //pridame aj vyreportovanie - prud svietidla - { - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - params.tbname = tbname; - params.address = node; - params.register = 75; - params.recipient = 1;//slave - params.rw = 0;//read - params.timestamp = priorityTypes.high_priority; - params.info = 'read Input Current (after set dimming from platform)'; - params.debug = true; - - tasks.push(params); - } - - //pridame aj vyreportovanie - power faktor - ucinnik - { - let params = getParams(priorityTypes.high_priority); - - params.type = "cmd"; - params.tbname = tbname; - params.address = node; - params.register = 77; - params.recipient = 1;//slave - params.rw = 0;//read - params.timestamp = priorityTypes.high_priority; - params.info = 'read power factor - Cos phi (after set dimming from platform)'; - params.debug = true; - - tasks.push(params); - } - - },4000); - - - nodeWasFound = true; - - break; - } - } - - if(!nodeWasFound) - { - logger.debug("set dimming from platform", "unable to find tbname", tbname); - } - } - else - { - instance.send(instanceSendTo.debug, "undefined command " + command); - logger.debug("undefined command", command); - } - - return; - - } - else if(method == "set_profile") - { - //nastav profil nodu - logger.debug("-->set_profile for node", data.params); - logger.debug("------profile data", profile); - //instance.send(instanceSendTo.debug, "set_profile" + command); - - let keys = Object.keys(nodesData); - for(let i = 0; i < keys.length; i++) - { - let node = keys[i]; - if(tbname == nodesData[node].tbname.trim()) - { - - 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"); - - //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, instanceSendTo.tb, instance, null ); - sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", {node: node}, profile, instanceSendTo.tb, instance ); - - nodesData[node].processed = false; - nodesData[node].profile = profile; - - let line = nodesData[node].line; - processNodeProfile(node); - - }); - }); - } - } - } - else - { - - instance.send(instanceSendTo.debug, "unknown method " + method); - logger.debug("unknown method", method); - - return; - } - - } - - //nastav profil linie z platformy - else if(entity_type == "edb_line" || entity_type == "edb") - { - //profil linie - //relays.table line:number|tbname:string|contactor:number|profile:string - //najdeme line relaysData - - 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++) - { - let line = keys[i]; - if(tbname == relaysData[line].tbname) - { - //zmazeme tasky - 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) { - - //update profile - logger.debug("worksys - update relay profile done:", profile); - instance.send(instanceSendTo.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, instanceSendTo.tb, instance ); - - }); - }); - - break; - } - } - } - else if(method == "set_command") - { - let value = data.params.payload.value; - - if(command === "switch") - { - - let responseRelays = await promisifyBuilder(dbRelays.find().where("tbname", 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"); - } - - } - else - { - instance.send(instanceSendTo.debug, "undefined method " + method); - logger.debug("undefined method", method); - } - - return; - - } - else{ - instance.send(instanceSendTo.debug, "UNKNOW entity_type " + entity_type); - logger.debug("UNKNOW entity_type", entity_type); - } - - return; - } - - //terminal - if(!rsPort.isOpen) await rsPort.open(); - - let params = flowdata.data.body; - if(params == undefined) - { - //logger.debug("CMD manager flowdata.data.body is undefined"); - return; - } - - params.priority = priorityTypes.terminal; - params.type = "cmd-terminal"; - params.tbname = ""; - params.timestamp = priorityTypes.terminal; - params.addMinutesToTimestamp = 0;// do not repeat task!!! - params.debug = true; - - let timestamp = Date.now(); - params.refFlowdataKey = timestamp; - //params.refFlowdata = flowdata; - //refFlowdata = flowdata; - - //console.log("flowdata", flowdata); - - cleanUpRefFlowdataObj(); - - refFlowdataObj[ timestamp ] = flowdata; - - //fix - //params.address = params.adress; - logger.debug("received from terminal", params); - logger.debug("date/time:", new Date()); - logger.debug("tasks length:", tasks.length); - - //tasks = []; - - //add to tasks - tasks.push(params); - - } - } - }) -} - - - - - - - - - - - - - - - - - - - - - - -///helper functions - -function calculateDuskDown(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; - -} +exports.id = 'cmd_manager'; +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.icon = 'cloud-upload'; +//exports.npm = ['serialport' , 'child_process']; + +exports.html = ` +
+
+
+
RPC - run RPC calls

+
+
+
@(User)
+
+
+
@(Password)
+
+
+
@(My edge)
+
+
+
+`; + +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 } = require('./helper/db_helper.js'); +const { sendNotification, initNotifications, ERRWEIGHT } = require('./helper/notification_reporter.js'); + +//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'); + +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"); + +//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 +let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89]; + +//1 - dimming + +const dbNodes = TABLE("nodes"); +const dbRelays = TABLE("relays"); +const dbSettings = TABLE("settings"); + +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 +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" + //params.tbname = tbname; + params.priority = priorityTypes.node_cmd;//default priority + params.timestamp = 0;//execution time + if(priority != undefined ) + { + params.timestamp = priority; + params.priority = priority; + } + + params.addMinutesToTimestamp = 0;//repeat if > 0, + + //params.isDusk = false; + //params.isDawn = false; + //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.log("", "settings", responseSettings[0], "-------------------------------------"); + logger.debug('settings', responseSettings[0]); + + //FLOW.OMS_tem + //rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number + + initNotifications(); +} + +//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) {} + + //test reset profilu + //nodeProfile = undefined; + + logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile); + //return; + + //let timestamp = priorityTypes.node_cmd; + + //let now = new Date(); + //now.setSeconds(now.getSeconds() + 10); + //let timestamp = now.getTime(); + + let timestamp = priorityTypes.node_cmd; + + //nodeProfile = undefined; + 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(priorityTypes.node_cmd); + params.type = "set_node_profile"; + params.address = node; + params.byte1 = 0; + params.byte2 = 0; + params.byte3 = 0; + params.byte4 = 32; + 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", "", instanceSendTo.tb, instance ); + } + else + { + let tasksProfile = []; + //cmdCounter[node] = tasksProfile.length; + //tasks.push(tasksProfile); + + //let timestamp = priorityTypes.node_cmd; + + //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu + let params = getParams(priorityTypes.node_cmd); + params.type = "set_node_profile"; + params.address = node; + params.byte1 = 0; + params.byte2 = 0; + params.byte3 = 0; + params.byte4 = 32; + 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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(priorityTypes.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(profile.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); + +} + +const instanceSendTo = { + debug: 0, + tb: 1, + http_response: 2, + dido_controller: 3, + infoSender: 4 +} + +const priorityTypes = { + 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 +} + + +let interval = null;//timeout for procesing tasks +let refFlowdata = null;//holds reference to httprequest flowdata +let refFlowdataObj = {}; + +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 ]; + } + } +} + +let tasks = [];//list of command calls to process + +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; + + }); + +} + + +//TODO - to remove? +const shortIterval = 10; +const longInterval = 100; + +loadSettings(); + +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); + }) + + //te();//force error + + const tbHandler = new DataToTbHandler(instanceSendTo.tb); + tbHandler.setSender(exports.title); + + //FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name + //const errorHandler = new ErrorToServiceHandler(instance, instanceSendTo.infoSender); + errorHandler.setProjectsId(FLOW.OMS_projects_id); + //const errorHandler = new ErrorToServiceHandler(instance); + //errorHandler.sendMessageToService("ahoj", 0); + + + async function loadRelaysData(line) + { + logger.debug("loadRelaysData", line); + + //ak zapiname liniu, mali by sme skontrolovat kde processed je false + //nodes.table: node:number|tbname:string|line:number|profile:string|processed:boolean + //vyselektujem vsetky nodes a spracujem profil + + return new Promise((resolve, reject) => { + + dbRelays.find().make(function(builder) { + builder.callback(function(err, response) { + + if(err != null) reject(err); + + let relaysDataTmp = {}; + for(let i = 0; i < response.length; i++) + { + let record = response[i]; + let line = record["line"]; + relaysDataTmp[ record["line"] ] = record; + + //porovname predchadzajuce hodnoty + //ak record.contactor == 1, a aktualna hodnota record.contactor == 0 + //to znamena, ze sa zmenil stav - linia bola vypnuta + + let prevData = relaysData[ record["line"] ]; + + //ugly but do not remove!!! + relaysData[ record["line"] ] = record; + + let state = "";//on, off or empty (no change) + if(prevData != undefined) + { + /* + if(prevData.contactor == 1 && record.contactor == 0) + { + state = "off"; + reportOfflineNodeStatus(line); + } + + if(prevData.contactor == 0 && record.contactor == 1) + { + state = "on"; + reportOnlineNodeStatus(line); + } + */ + + } + else + { + //start flowu + state = "start"; + } + + if(line != undefined) + { + //ak sa jedna o update profilu linie - pozor di_co_controller posiela command pre loadRelaysData + if(line != record["line"] ) continue; + } + + //je zapnuta linia? contactor = 1 a processed = false, spracujeme profil + if(record.contactor == 1) + { + + //nespracovany profil, zapisem do nodu + //rotary_switch_state = Automatic - profilu pre nody sa vykonavaju + //ak je spracovany, a automatic - tak ho zapnem + + if(rotary_switch_state == "Automatic") + { + //prejs nodes - nacitame vsetky nody z pre danu liniu + for (let k in nodesData) { + //node:number|tbname:string|line:number|profile:string|processed:boolean + + //potrebujem nody k danej linii + if(record.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`); + } + } + } + + } + else + { + logger.debug("unable to process profile - rotary_switch_state is", rotary_switch_state); + } + + } + } + + relaysData = {...relaysDataTmp}; + + resolve("OK"); + + }); + }); + //resolve(stdout); + //reject(error); + + }) + } + + function reportOnlineNodeStatus(line) + { + //broadcast cas, o 1-2 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 + params.byte1 = hours;//h + params.byte2 = minutes;//m + params.byte3 = seconds;//s + params.byte4 = 0; + params.recipient = recipient; + params.register = 87;//Actual time + params.rw = 1;//write + + let timestampStart = priorityTypes.node_broadcast; + + //other values + params.type = "cmd"; + //params.tbname = tbname; + params.timestamp = timestampStart; + params.addMinutesToTimestamp = addMinutesToTimestamp; + params.info = "run broadcast: Actual time"; + + tasks.push(params); + + let sec = 3; + 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) + { + let tbname = nodesData[k].tbname; + let node = nodesData[k].node; + + //prud, vykon - current, input power pre liniu pre vsetky nody + + //a pridame aj vyreportovanie dimmingu + { + let params = getParams(priorityTypes.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 = priorityTypes.high_priority; + params.info = 'read dimming / brightness (after set dimming from platform)'; + //params.debug = true; + + tasks.push(params); + } + + //Prúd + { + let params = getParams(priorityTypes.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 75;//prud + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = priorityTypes.high_priority; + params.info = 'read current (after set dimming from platform)'; + //params.debug = true; + + tasks.push(params); + } + + //výkon + { + let params = getParams(priorityTypes.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 76;//výkon + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = priorityTypes.high_priority; + params.info = 'read power (after set dimming from platform)'; + //params.debug = true; + + tasks.push(params); + } + + } + } + + },sec*1000); + + } + + } + + 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; + + //logger.debug("node:", tbname); + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + } + } + + //report OFFLINE for line + //relaysData[line].tbname; + + //values = {}; + //values["status"] = "OFFLINE";//prúd + } + + let now = new Date(); + console.log("CMD Manager installed", now.toLocaleString("sk-SK")); + + function turnOnLine(line, info) + { + let obj = { + line: line, + command: "turnOn", + info: info + }; + + logger.debug("linia", line, obj); + + instance.send(instanceSendTo.dido_controller, obj); + } + + function turnOffLine(line, info) + { + let obj = { + line: line, + command: "turnOff", + info: info + }; + + logger.debug("linia", line, obj); + + instance.send(instanceSendTo.dido_controller, obj); + } + + 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"; + else type = "UNKNOWN"; + + 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]) + { + //CRC_ERROR + message = "NOK"; + error = "CRC_ERROR c1"; + instance.send(instanceSendTo.debug, "CRC_ERROR c1"); + } + + if(c2 != bytes[10]) + { + //CRC_ERROR + message = "NOK"; + error = "CRC_ERROR c2"; + instance.send(instanceSendTo.debug, "CRC_ERROR c2"); + } + + //crc error + if(type != "RESPONSE") + { + instance.send(instanceSendTo.debug, bytes); + instance.send(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4]); + + //logger.debug(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4], bytes); + + error = "type is: " + type; + + message = "NOK"; + } + + return {message: message, type: type, error: error}; + } + + function buildTasks(params) + { + + //report FLOW.OMS_edge_fw_version as fw_version + //report date as startdate + + monitor.info("buildTasks - params", params); + + let processLine; //defined line + + let init = false; + let processLineProfiles = true; + let processBroadcast = true; + let processNodes = true; + + if(params == undefined) + { + init = true; + tasks = []; + + logger.debug("-->buildTasks clear tasks"); + } + else + { + processLineProfiles = false; + processBroadcast = false; + processNodes = false; + + processLineProfiles = params.processLineProfiles; + processLine = params.line; + } + + //load profiles pre linie + //relaysData[ record["line"] ] + + let now = new Date(); + + if(processLineProfiles) + { + //process line profiles + let keys = Object.keys(relaysData); + for(let i = 0; i < keys.length; i++) + { + let line = keys[i];//line is turned off by default + let profilestr = relaysData[line].profile; + + //Reset linii + let resetLine = false; + if(FLOW.OMS_rvo_name == "Kovalov RVO 2" && line != '0' && init == true) resetLine = true; + + if(resetLine) + { + /* + + Takže v Koválove sú nastavené offesty pre dusk a dawn nasledovne: + + DUSK: offset +20 minút – teda napr. namiesto 17:00 bude 17:20 a reštart by sa robil v čase 17:19, teda o minútu skôr. Tak aby keď budeš robiť zapnutie o 17:20 tak na RVO1 sa svietidlá zapnú v rovnakom čase. Teda: vypnutie v čase DUSK_TIME + 19 minút, zapnutie v čase DUSK_TIME + 20 minút + DAWN: offset -30 minút – teda napr. namiesto 7:00 bude 6:30 a reštart by sa robil v čase 6:30, tak aby sa svietidlá zhasli rovnako s RVO1. Zapnutie by bolo 6:31. + + Teda: vypnutie v čase DAWN_TIME -30 minút, zapnutie v čase DAWN_TIME -29 minút + + Vždy po reštarte asi 30 sekúnd po zapnutí treba poslať aktuálny čas na nody. + */ + + //function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) + let duskOffset = 20; + let dawnOffset = -30; + let sunCalcResult = calculateDuskDown(new Date(), undefined, duskOffset, dawnOffset); + + console.log(sunCalcResult); + monitor.info("--> dusk - dawn", sunCalcResult); + + //if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo + //if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo + + //DUSK - sumrak + { + + //vypneme liniu a o minitu zapneme + { + let value = 0;//vypneme liniu + let isDusk = true; + let isDawn = false; + + let dusk_time = sunCalcResult.dusk_time; + if(dusk_time < now.getTime()) dusk_time = dusk_time + 24*60*60*1000;//1den + + let params = getParams(priorityTypes.relay_profile); + params.type = "relay"; + params.line = line; + params.value = value; + params.tbname = relaysData[line].tbname; + params.timestamp = dusk_time; + params.duskOffset = duskOffset; + params.useProfile = false; + + //once a day + params.addMinutesToTimestamp = 24*60; + + //this will be recalculated + params.isDusk = isDusk; + params.isDawn = isDawn; + + if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; + else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; + + params.debug = true; + + //turn on/off line + tasks.push(params); + + console.log(params); + } + + //a o minutu zapneme + { + let value = 1;//zapneme liniu + let isDusk = true; + let isDawn = false; + + let dusk_time = sunCalcResult.dusk_time + 60*1000;//o minutu neskor po vypnuti zapneme + if(dusk_time < now.getTime()) dusk_time = dusk_time + 24*60*60*1000;//1den + + let params = getParams(priorityTypes.relay_profile); + params.type = "relay"; + params.line = line; + params.value = value; + params.tbname = relaysData[line].tbname; + params.timestamp = dusk_time; + params.duskOffset = duskOffset + 1; + params.useProfile = false; + + //once a day + params.addMinutesToTimestamp = 24*60; + + //this will be recalculated + params.isDusk = isDusk; + params.isDawn = isDawn; + + if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; + else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; + + params.debug = true; + + //turn on/off line + tasks.push(params); + + console.log(params); + } + + + } + + //DAWN - vychod + { + //vypneme liniu a o minitu zapneme + { + let value = 0;//vypneme liniu + let isDusk = false; + let isDawn = true; + + let dawn_time = sunCalcResult.dawn_time; + if(dawn_time < now.getTime()) dawn_time = dawn_time + 24*60*60*1000;//1den + + let params = getParams(priorityTypes.relay_profile); + params.type = "relay"; + params.line = line; + params.value = value; + params.tbname = relaysData[line].tbname; + params.timestamp = dawn_time; + + params.dawnOffset = dawnOffset; + params.useProfile = false; + + //once a day + params.addMinutesToTimestamp = 24*60; + + //this will be recalculated + params.isDusk = isDusk; + params.isDawn = isDawn; + + if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; + else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; + + params.debug = true; + + //turn on/off line + tasks.push(params); + + console.log(params); + } + + //a o minitu zapneme + { + let value = 1;//vypneme liniu + let isDusk = false; + let isDawn = true; + + let dawn_time = sunCalcResult.dawn_time + 1000*60;//o minutu neskor po vypnuti zapneme + if(dawn_time < now.getTime()) dawn_time = dawn_time + 24*60*60*1000;//1den + + let params = getParams(priorityTypes.relay_profile); + params.type = "relay"; + params.line = line; + params.value = value; + params.tbname = relaysData[line].tbname; + params.timestamp = dawn_time; + + params.dawnOffset = dawnOffset + 1; + params.useProfile = false; + + //once a day + params.addMinutesToTimestamp = 24*60; + + //this will be recalculated + params.isDusk = isDusk; + params.isDawn = isDawn; + + if(params.value == 0) params.info = "reset - KOVALOV - force turn off line: " + line; + else if(params.value == 1) params.info = "reset - KOVALOV - force turn on line: " + line; + + params.debug = true; + + //turn on/off line + tasks.push(params); + + console.log(params); + } + + + } + + //console.log("-------------------------Kovalov RVO 2----"); + } + + if(processLine != undefined) + { + if(processLine != line) continue; + } + + try{ + + if(profilestr === "") throw ("profile is not defined"); + let profile = JSON.parse(profilestr); + if(Object.keys(profile).length === 0) throw ("profile is not defined"); + + 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; + + //monitor.info("buildTasks: time_points", time_points); + + let currentValue = 0; + if(time_points.length > 0) currentValue = time_points[ time_points.length - 1].value; + + //create task for tun on + turn off, calculate dusk/down + if(profile.astro_clock == true) + { + //let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"}); + let sunCalcResult = calculateDuskDown(new Date(), line); + + // monitor.info("dusk and dawn sunCalcResult", line, sunCalcResult); + + //add to timpoints + if(profile.dawn_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dawn"], "value": 1, "isDawn": true} ); + if(profile.dusk_lux_sensor == false) time_points.push( {"start_time": sunCalcResult["dusk"], "value": 0, "isDusk": true} ); + + //aby nam to neostalo svietit + if(profile.dawn_lux_sensor == true) + { + //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window + 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); + + let strDate = ad.getHours() + ":" + ad.getMinutes(); + + time_points.push( {"value": 0, "start_time": strDate} ); + } + + if(profile.dusk_lux_sensor == true) + { + //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window + let [ahours, aminutes, aseconds] = sunCalcResult["dusk"].split(':'); + + let ad = new Date(); + ad.setHours( parseInt(ahours) ); + ad.setMinutes( parseInt(aminutes) + profile.dawn_lux_sensor_time_window ); + ad.setSeconds(0); + + let strDate = ad.getHours() + ":" + ad.getMinutes(); + + time_points.push( {"value": 1, "start_time": strDate} ); + } + } + + //sort time_points + 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(); + }); + + monitor.info("-->comming events turn on/off lines:"); + for(let t = 0; t < time_points.length; t++) + { + + let start_time = new Date(); + + let isDusk = false; + let isDawn = false; + if(time_points[t].hasOwnProperty("isDusk")) isDusk = time_points[t].isDusk; + if(time_points[t].hasOwnProperty("isDawn")) isDawn = time_points[t].isDawn; + + if(isDusk) time_points[t].value = 1;//sumrak - zapneme svetlo + if(isDawn) time_points[t].value = 0;//vychod - vypneme svetlo + + if(time_points[t].hasOwnProperty("start_time")) + { + let [hours, minutes, seconds] = time_points[t].start_time.split(':'); + + start_time.setHours( parseInt(hours) ); + start_time.setMinutes( parseInt(minutes) ); + start_time.setSeconds(0); + } + + //task is the past + if(now.getTime() > start_time.getTime()) + { + currentValue = time_points[t].value; + + //je v minulosti, pridame 24h + start_time.setDate(start_time.getDate() + 1); + } + + let params = getParams(priorityTypes.relay_profile); + params.type = "relay"; + params.line = line; + params.value = time_points[t].value; + params.tbname = relaysData[line].tbname; + params.timestamp = start_time.getTime(); + + params.addMinutesToTimestamp = 0; + + //once a day + if(!isDusk && !isDawn) params.addMinutesToTimestamp = 24*60; + + //inak sa cas vypocita dynamicky + + //this will be recalculated + params.isDusk = isDusk; + params.isDawn = isDawn; + + //if(profile.astro_clock == true && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) + + if(params.value == 0) + { + params.info = "turn off line: " + line; + if(isDusk) params.info = "dusk: turn off line: " + line; + if(isDawn) params.info = "dawn: turn off line: " + line; + } + else if(params.value == 1) + { + params.info = "turn on line: " + line; + if(isDusk) params.info = "dusk: turn on line: " + line; + if(isDawn) params.info = "dawn: turn on line: " + line; + } + + params.debug = true; + + //turn on/off line + tasks.push(params); + + monitor.info(params.info, start_time); + + } + + monitor.info("-->time_points final", line, time_points); + + //ensure to turn on/off according to calculated value + let params = getParams(priorityTypes.terminal); + params.type = "relay"; + params.line = parseInt(line); + params.tbname = relaysData[line].tbname; + params.value = currentValue; + params.isDusk = false; + params.isDawn = false; + + params.timestamp = priorityTypes.terminal; + params.addMinutesToTimestamp = 0; + params.debug = true; + + //logger.debug(now.toLocaleString("sk-SK")); + 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; + + tasks.push(params); + + + } catch (error) { + if(profilestr !=="" ) + { + //errLogger.error(profilestr, error); + errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error"); + } + } + + } + + //logger.debug("tasks:"); + //logger.debug(tasks); + } + + + //PROCESS DEFAULT BROADCASTS + + //RPC pre nody / broadcast + //Time of dusk, Time of dawn + //Actual Time + + if(processBroadcast) + { + let addMinutesToTimestamp = 5; + + { + //run broadcast Time of dusk + // addMinutesToTimestamp = 60*5; + addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk + + let params = getParams(priorityTypes.node_broadcast); + + let recipient = 2;//2 broadcast, address = 0 + let address = 0;//0 + if(recipient === 2) + { + address = 0xffffffff;//Broadcast + } + + let sunCalcResult = calculateDuskDown(); + let dusk_hours = sunCalcResult["dusk_hours"]; + let dusk_minutes = sunCalcResult["dusk_minutes"]; + + params.address = address;//broadcast + params.byte1 = dusk_hours;//h + params.byte2 = dusk_minutes;//m + params.byte3 = 0;//s + params.byte4 = 0; + params.recipient = recipient; + params.register = 6;//Time of dusk - Reg 6 + params.rw = 1;//write + + let timestampStart = priorityTypes.node_broadcast; + + //other values + params.type = "cmd"; + //params.tbname = tbname; + params.timestamp = timestampStart; + 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(priorityTypes.node_broadcast); + + let recipient = 2;//2 broadcast, address = 0 + let address = 0;//0 + if(recipient === 2) + { + address = 0xffffffff;//Broadcast + } + + let sunCalcResult = calculateDuskDown(); + let dawn_hours = sunCalcResult["dawn_hours"]; + let dawn_minutes = sunCalcResult["dawn_minutes"]; + + params.address = address;//broadcast + params.byte1 = dawn_hours;//h + params.byte2 = dawn_minutes;//m + params.byte3 = 0;//s + params.byte4 = 0; + params.recipient = recipient; + params.register = 7;//Time of dawn - Reg 6 + params.rw = 1;//write + + let timestampStart = priorityTypes.node_broadcast; + + //other values + params.type = "cmd"; + //params.tbname = tbname; + params.timestamp = timestampStart; + params.addMinutesToTimestamp = addMinutesToTimestamp; + params.info = "Broadcast-dawnTime"; + + tasks.push(params); + } + + + { + //run broadcast //Actual time + addMinutesToTimestamp = 5; + + let params = getParams(priorityTypes.node_broadcast); + + 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 + params.byte1 = hours;//h + params.byte2 = minutes;//m + params.byte3 = seconds;//s + params.byte4 = 0; + params.recipient = recipient; + params.register = 87;//Actual time + params.rw = 1;//write + + let timestampStart = priorityTypes.node_broadcast; + + //other values + params.type = "cmd"; + //params.tbname = tbname; + params.timestamp = timestampStart; + params.addMinutesToTimestamp = addMinutesToTimestamp; + params.info = "run broadcast: Actual time"; + + tasks.push(params); + + } + + { + //run broadcast Actual Lux level from cabinet + + //Do tohto registra posiela riadiaca jednotka hodnotu intenzity osvetlenia ktorú meria jej senzor pre potreby riadenia časov súmraku resp. úsvitu podľa intenzity osvetlenia. + //Byty 0 (LSB) a 1 obsahujú 16 bitový integer s luxami. + + let params = getParams(priorityTypes.node_broadcast); + + addMinutesToTimestamp = 15; + + let recipient = 2;//2 broadcast, address = 0 + let address = 0;//0 + if(recipient === 2) + { + address = 0xffffffff;//Broadcast + } + + //TODO + //16 bitový integer s luxami + params.byte3 = lux_sensor; + params.byte4 = lux_sensor; + params.timestamp = priorityTypes.node_broadcast; + params.addMinutesToTimestamp = addMinutesToTimestamp; + params.info = "run broadcast: Actual Lux level from cabinet"; + params.register = 95;//Actual Lux level from cabinet + params.rw = 1;//write + + } + } + + //process nodes & tasks + //reportovanie pre platformu + 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++) + { + register = listOfCommands[i]; + + let params = getParams(priorityTypes.node_cmd); + + //core rpc values + params.address = address; + params.byte1 = 0; + params.byte2 = 0; + params.byte3 = 0; + params.byte4 = 0; + params.recipient = 1; + params.register = register; + params.rw = 0; + + let addMinutesToTimestamp = priorities[register]; + + let timestampStart = priorityTypes.node_cmd; //run imediatelly in function runTasks + 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; + + + //Priebežne (raz za cca 5 minút) je potrebné vyčítať z Master nodu verziu jeho FW. + //Jedná sa o register 10. Rovnaká interpretácia ako pri FW verzii nodu. + //Adresa mastera je 0. V prípade že kedykoľvek nastane situácia že Master Node neodpovedá (napríklad pri vyčítaní telemetrie z nodu nevráti žiadne dáta), + //tak treba vyreportovať string "NOK". + { + let params = getParams(priorityTypes.fw_detection); + params.type = "cmd"; + params.register = 4; + params.address = 0; + + let timestampStart = priorityTypes.fw_detection; + params.timestamp = timestampStart; + params.addMinutesToTimestamp = 5; + params.tbname = FLOW.OMS_edgeName; + params.info = "Master node FW verzia"; + //params.debug = true; + + //this will set FLOW.OMS_masterNodeIsResponding + + tasks.push(params); + } + + //kazdu hodinu skontrolovat nastavenie profilov + { + let params = getParams(priorityTypes.fw_detection); + params.type = "process_profiles"; + + let timestampStart = priorityTypes.relay_profile; + params.timestamp = timestampStart; + 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(priorityTypes.node_cmd); + params.type = "edge_date_time"; + + let timestampStart = priorityTypes.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(priorityTypes.node_cmd); + params.type = "number_of_luminaires"; + + let timestampStart = priorityTypes.node_cmd + 1; + params.timestamp = timestampStart; + params.addMinutesToTimestamp = 1; + params.tbname = FLOW.OMS_edgeName; + params.info = "reportovanie number_of_luminaires"; + + tasks.push(params); + } + + monitor.info("tasks created:", tasks.length); + } + + function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) + { + //let dusk_hours = sunCalcResult["dusk_hours"]; + //let dusk_minutes = sunCalcResult["dusk_minutes"]; + + let duskTimeStamp; + let downTimeStamp; + + //prejedme si line s profilom, kde mame "astro_clock": true + + /* + "dawn_lux_sensor": true, + "dusk_lux_sensor": true, + "dawn_lux_sensor_value": 5, + "dusk_lux_sensor_value": 5, + "dawn_astro_clock_offset": 0, + "dusk_astro_clock_offset": 10, + "dawn_lux_sensor_time_window": 30, + "dusk_lux_sensor_time_window": 30, + "dawn_astro_clock_time_window": 60, + "dusk_astro_clock_time_window": 60 + */ + + //ak sme pred/po vychode a lux value <= lux_sensor_value, liniu zapneme + + //ak sme pred/po zapade a lux_value <= lux_sensor_value, liniu zapneme + + let now = new Date(); + let currentTimestamp = now.getTime(); + + let keys = Object.keys(relaysData); + for(let i = 0; i < keys.length; i++) + { + let line = keys[i];//line is turned off by default + let profilestr = relaysData[line].profile; + let contactor = relaysData[line].contactor; // 0 or 1 - vypnuta/zapnuta + + try{ + + let profile = JSON.parse(profilestr); + if(Object.keys(profile).length === 0) throw ("profile is not defined"); + + if(profile.astro_clock == true) + { + let sunCalcResult = calculateDuskDown(now, line); + + //dawn: usvit/vychod - lux je nad hranicou - vypnem + //dusk: zapad pod hranicou - zapnem + + //"dawn_lux_sensor_time_window": 30, + //"dusk_lux_sensor_time_window": 30, + + //vychod + // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut + if(profile.dawn_lux_sensor == true) + { + let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); + let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); + //console.log('------>>>', new Date(lux_sensor_time_window1), new Date(lux_sensor_time_window2), lux_sensor_time_window1, lux_sensor_time_window2) + //console.log('++++-->>>', new Date(sunCalcResult.dusk_time), new Date(sunCalcResult.dawn_time)) + + if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) + { + //dawn: usvit/vychod - lux je nad hranicou - vypnem + if(lux_sensor_value > profile.dawn_lux_sensor_value) + { + //vypnem + if(contactor) turnOffLine(line, "profile: dawn - turnOff line according to lux sensor"); + } + // else + // { + // //zapnem + // if(!contactor) turnOnLine(line, "profile: dawn - turnOn line according to lux sensor"); + // } + + } + + //ak sme po vychode + if(currentTimestamp > lux_sensor_time_window2) + { + //vypneme + //urobime jednorazovy prikaz + } + } + + //zapad + 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) + { + //dusk: zapad pod hranicou - zapnem + if(lux_sensor_value < profile.dusk_lux_sensor_value) + { + //zapnem + if(!contactor) turnOnLine(line, "profile: dusk - turnOn line according to lux sensor"); + } + // else + // { + // //vypnem + // if(contactor) turnOffLine(line, "profile: dusk - turnOff line according to lux sensor"); + // } + + } + } + + + } + + } catch (error) { + //if(profilestr !=="" ) logger.debug(profilestr, error); + } + } + } + + let sunCalcResult = calculateDuskDown(); + + let reportDuskDawn = { + dusk_time: sunCalcResult.dusk_time, + dawn_time: sunCalcResult.dawn_time, + dusk_time_reported: undefined, + dawn_time_reported: undefined + }; + + async function upateNodeStatus(node, status) + { + //MASTER + if(node == 0) return; + + let nodeObj = nodesData[node]; + if(nodeObj == undefined) return; + + if(status) + { + cmdNOKNodeCounter[node] = 0; + } + 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; + }); + }); + } + } + + + async function runTasks() { + + clearInterval(interval); + + let currentTimestamp = Date.now(); + + //report dusk, dawn--------------------------------- + if(reportDuskDawn.dusk_time < currentTimestamp) + { + //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund + 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"]}, "", instanceSendTo.tb, instance); + reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time; + } + } + + var nextDay = new Date(); + nextDay.setDate(nextDay.getDate() + 1); + + sunCalcResult = calculateDuskDown(nextDay); + reportDuskDawn.dusk_time = sunCalcResult.dusk_time; + } + + if(reportDuskDawn.dawn_time < currentTimestamp) + { + //vyreportuj iba ak nie je velky rozdiel napr. 60 sekund + 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"]}, "", instanceSendTo.tb, instance); + reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time; + } + } + + var nextDay = new Date(); + nextDay.setDate(nextDay.getDate() + 1); + + sunCalcResult = calculateDuskDown(nextDay); + reportDuskDawn.dawn_time = sunCalcResult.dawn_time; + + } + //-------------------------------------------------------- + + //sort tasks + //tasks.sort((a,b) => a.timestamp - b.timestamp ); + + 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 ) + { + instance.send(instanceSendTo.debug, "no tasks created"); + interval = setInterval(runTasks, longInterval); + + return; + } + + if(!rsPort.isOpen) + { + instance.send(instanceSendTo.debug, "!rsPort.isOpen"); + //await rsPort.open(); + + //continue + } + + let currentTask = tasks[0]; + + if(currentTask.debug) + { + //logger.debug("--->task to process", currentTask); + } + + if(currentTask.timestamp <= currentTimestamp) + { + let params = {...tasks[0]}; + + if(FLOW.OMS_maintenance_mode) + { + + //allow terminal commands + if(params.type == "cmd-terminal"); + else + { + interval = setInterval(runTasks, longInterval); + return; + } + } + + let type = params.type; + let tbname = params.tbname; + let nodeKey = params.address; + + let useProfile = params.useProfile; + if(useProfile === undefined) useProfile = true; + let duskOffset = params.duskOffset; + let dawnOffset = params.dawnOffset; + + let line = null; + //rpc related + if(nodesData[nodeKey] !== undefined) line = nodesData[nodeKey].line; + if(params.line !== undefined) line = params.line; + + let repeatTask = false; + if(params.addMinutesToTimestamp > 0) repeatTask = true; + if(params.isDawn || params.isDusk) repeatTask = true; + + if(repeatTask) + { + if(type == "cmd") + { + //set next start time automatically + tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; + } + } + else + { + //terminal data... + 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(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + + interval = setInterval(runTasks, shortIterval); + + return; + } + } + + + + //kontrola nespracovanych profilov nodov + 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(); + + interval = setInterval(runTasks, shortIterval); + return; + } + + if(type == "edge_date_time") + { + + //var d = new Date(); + //let hours = addZeroBefore(d.getHours()); + //let minutes = addZeroBefore(d.getMinutes()); + //let seconds = addZeroBefore(d.getSeconds()); + //let values = {"edge_date_time": `${hours}:${minutes}:${seconds}`}; + + let values = {"edge_date_time": Date.now()}; + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; + + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + + interval = setInterval(runTasks, shortIterval); + + return; + } + + //relay + if(type == "relay") + { + + //ak je dusk, alebo dawn, vypocitame si dynamicky nove values + if(params.isDawn || params.isDusk) + { + let date = new Date(); + date.setDate(date.getDate() + 1);//next day + + let sunCalcResult; + if(useProfile) sunCalcResult = calculateDuskDown(date, params.line); + else + { + //do not use profile, line is there for undefined + sunCalcResult = calculateDuskDown(date, undefined, duskOffset, dawnOffset); + } + + if(params.isDawn) + { + tasks[0].timestamp = sunCalcResult.dawn_time; + } + + if(params.isDusk) + { + tasks[0].timestamp = sunCalcResult.dusk_time; + } + } + else + { + if(tasks[0].addMinutesToTimestamp == 0);// tasks.shift(); + else tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; + } + + let info; + if(useProfile) info = "aplikovaný bod profilu"; + else info = params.info; + + let message = ""; + if(params.value == 1) + { + turnOnLine(params.line, info); + message = "on"; + } + else if(params.value == 0) + { + turnOffLine(params.line, info); + message = "off"; + } + + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", instanceSendTo.tb, instance, null ); + if(useProfile) sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", instanceSendTo.tb, instance ); + + interval = setInterval(runTasks, shortIterval); + return; + } + + //zhodeny hlavny istic + let disconnected = false; + //if(rotary_switch_state == "Off") disconnected = true; + + //state_of_breaker[line] - alebo istic linie + if(state_of_breaker.hasOwnProperty(line)) + { + //if(state_of_breaker[line] == "Off") disconnected = true; + } + + //toto sa reportuje po prijati dat z di_do_controlera + 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[tbname]) + { + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + } + + interval = setInterval(runTasks, shortIterval); + + return; + } + + disconnectedReport[tbname] = false; + + //high_priority + if(!FLOW.OMS_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) + { + interval = setInterval(runTasks, longInterval); + return; + } + + } + + let relayStatus = 1; + if(relaysData[line] != undefined) + { + relayStatus = relaysData[line].contactor; + } + + if(line == 0) relayStatus = 0; + if(params.type == "cmd-terminal") relayStatus = 1; + + //check if rotary_switch_state == "Off" + + if(relayStatus == 0) + { + //console.log("------------------------------------relayStatus", relayStatus, line); + let values = {"status": "OFFLINE"}; + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + + interval = setInterval(runTasks, shortIterval); + + return; + } + + if(!rsPort.isOpen) + { + interval = setInterval(runTasks, longInterval); + return; + } + + //RE-CALCULATE VALUES + //set actual time for broadcast + if(params.register == 87 && params.recipient === 2) + { + var d = new Date(); + let hours = d.getHours(); + let minutes = d.getMinutes(); + let seconds = d.getSeconds(); + + params.byte1 = hours;//h + params.byte2 = minutes;//m + params.byte3 = seconds;//s + params.byte4 = 0; + } + + //set dusk/down for broadcast + + //Time of dusk + if(params.register == 6 && params.recipient === 2) + { + + if(params.type != "cmd-terminal") + { + let sunCalcResult = calculateDuskDown(); + 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 + params.byte4 = 0; + + //TODO astrohodiny + let dusk = "Time of dusk: " + sunCalcResult["dusk"]; + //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", instanceSendTo.tb, instance, null ); + } + } + + //Time of dawn + if(params.register == 7 && params.recipient === 2) + { + if(params.type != "cmd-terminal") + { + let sunCalcResult = calculateDuskDown(); + 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 + params.byte4 = 0; + + //TODO astrohodiny + let dawn = "Time of dawn: " + sunCalcResult["dawn"]; + //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", instanceSendTo.tb, instance, null ); + } + + } + //----------------------- + + + let register = params.register; + instance.send(instanceSendTo.debug, "address: " + params.address + " register:" + params.register + "type: " + params.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; + + //if broadcast WRITE - do not read + //if(params.recipient == 2) readBytes = 0; + + //WRITE + BROADCAST = readBytes = 0; + // if(params.rw == 1 && params.recipient == 2) readBytes = 0; + + if(params.hasOwnProperty("debug")) + { + //console.log("--->readBytes", readBytes, params); + } + + await writeData(rsPort, resp, readBytes).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; + + //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK + + if(params.debug != "generated cmd") + { + //debug("writeData: done " + type + " duration: " + timeDiff + " type: " + params.debug, params); + } + + if(params.hasOwnProperty("debug")) + { + if(params.debug) + { + console.log("detected response:", result); + + logger.debug("writeData: done " + type + " 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); + + let tbname = params.tbname; + + let saveToTb = true; + if(tbname == null || tbname == undefined || tbname == "") saveToTb = false; + //-- + + //CMD FINISHED + if(message == "OK") + { + + upateNodeStatus(params.address, 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) { + + builder.callback(function(err, response) { + + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "dimming_profile_was_successfully_received_by_node", {node: params.address}, "", instanceSendTo.tb, instance ); + + logger.debug( "--> profil úspešne odoslaný na node č. " + params.address); + nodesData[params.address].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.register == 0) values["status"] = message; + + //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", "", instanceSendTo.tb, instance, "rvo_status" ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", instanceSendTo.tb, instance, "rvo_status" ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_responding_again", {}, "", instanceSendTo.tb, instance, "rvo_status" ); + FLOW.OMS_masterNodeIsResponding = true; + } + + //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, instanceSendTo.tb, instance, null ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "command_was_sent_from_terminal_interface", {}, params, instanceSendTo.tb, instance ); + } + + if(params.debug) + { + logger.debug("saveToTb", saveToTb, tbname, values); + } + + if(saveToTb) + { + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + + } + 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(instanceSendTo.http_response, params.refFlowdata); + + let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; + refFlowdata.data = responseObj; + instance.send(instanceSendTo.http_response, refFlowdata); + + } + else + { + console.log("params.refFlowdataKey is undefined", params); + } + } + + } + + } + else + { + + upateNodeStatus(params.address, false); + + 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(instanceSendTo.http_response, params.refFlowdata); + + let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; + if(refFlowdata !== undefined) + { + refFlowdata.data = responseObj; + instance.send(instanceSendTo.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(instanceSendTo.http_response, params.refFlowdata); + + } + } + */ + + if(params.address == 0) + { + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", instanceSendTo.tb, instance, "rvo_status"); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", instanceSendTo.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, "", instanceSendTo.tb, instance, null ); + sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.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(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + } + + //instance.send(instanceSendTo.debug, result); + + if(params.hasOwnProperty("debug")) + { + if(params.debug) + { + logger.debug("writeData err: ", error, result, params); + } + } + + //logger.debug(error, result, params); + } + + }).catch(function (reason) { + + console.log("writeData catch exception", reason); + logger.debug(currentTask); + + if(params.refFlowdataKey != undefined) + { + + 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(instanceSendTo.http_response, params.refFlowdata); + + let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; + if(refFlowdata !== undefined) + { + refFlowdata.data = responseObj; + instance.send(instanceSendTo.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(instanceSendTo.http_response, params.refFlowdata); + + //refFlowdata = undefined; + } + } + */ + + 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", "", instanceSendTo.tb, instance, "rvo_status"); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", instanceSendTo.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", "", instanceSendTo.tb, instance, null ); + sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", instanceSendTo.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(instanceSendTo.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(instanceSendTo.tb, dataToTb); + } + */ + + instance.send(instanceSendTo.debug, reason); + }); + + } + else + { + if(currentTask.debug) + { + //currentTask.timestamp <= currentTimestamp + logger.debug("currentTask is not processed - task is in the future", currentTask); + } + + interval = setInterval(runTasks, longInterval); + return; + } + + //console.log("----->runTasks - setInterval", new Date()); + interval = setInterval(runTasks, shortIterval); + } + + //! 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 = "ttymxc4"; + if(FLOW.OMS_serial_port == undefined) FLOW.OMS_serial_port = "ttymxc4"; + if(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); + + rsPort.on('open', async function() { + + logger.debug("CMD manager - rsPort opened sucess"); + + await loadRelaysData(); + + 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(instanceSendTo.debug, "RPC runSyncExec - Promise Resolved:" + status); + + logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status); + + //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(instanceSendTo.infoSender, dataToInfoSender); + + logger.debug(0, "---------------------------->START message send to service", dataToInfoSender); + + //---- + + nodesData = {}; + + dbNodes.find().make(function(builder) { + builder.callback(function(err, response) { + + for(let i = 0; i < response.length; i++) + { + let node = response[i]; + let key = node["node"]; + + nodesData[ key ] = node; + } + + //buildTasks(); + //interval = setInterval(runTasks, longInterval); + // console.log('******** nodesData',nodesData); + + }); + }); + + }).catch(function (reason) { + instance.send(instanceSendTo.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason); + }); + + }); + + 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); + + instance.send(instanceSendTo.debug, err.message); + }); + + rsPort.on("close", () => { + rsPort.close(); + }); + + //loadRelaysData(); + rsPort.open(); + + instance.on("close", () => { + clearInterval(interval); + rsPort.close(); + }); + + //onData + instance.on("data", async function(flowdata) { + //instance.on("data", (data) => { + + //instance.send(instanceSendTo.debug, "on Data"); + //instance.send(instanceSendTo.debug, flowdata); + + //logger.debug(flowdata.data); + + //just testing functions + if(flowdata.data == "open") + { + if(!rsPort.isOpen) rsPort.open(); + return; + } + else if(flowdata.data == "close") + { + rsPort.close(); + return; + } + else if(flowdata.data == "clean") + { + tasks = []; + return; + } + else if(flowdata.data == "buildtasks") + { + //build & run + return; + } + else if(flowdata.data == "run") + { + //durations = []; + + if(tasks.length == 0) + { + + buildTasks(); + + if(rsPort.isOpen) + { + interval = setInterval(runTasks, 100); + } + else + { + instance.send(instanceSendTo.debug, "port is not opened!!!"); + } + } + } + else + { + //terminal data - object + //logger.debug("flowdata", flowdata.data); + + if(typeof flowdata.data === 'object') + { + //logger.debug("dido", flowdata.data); + if(flowdata.data.hasOwnProperty("sender")) + { + //data from dido_controller + if(flowdata.data.sender == "dido_controller") + { + + if(flowdata.data.hasOwnProperty("cmd")) + { + let cmd = flowdata.data.cmd; + + + if(cmd == "buildTasks") + { + clearInterval(interval); + + logger.debug("-->CMD MANAGER - BUILD TASKS"); + buildTasks(); + + //logger.debug("tasks:"); + //logger.debug(tasks); + + logger.debug("-->CMD MANAGER - RUN TASKS"); + interval = setInterval(runTasks, longInterval); + } + else if(cmd == "reload_relays") + { + await loadRelaysData(flowdata.data.line); + + if(flowdata.data.dataChanged) + { + if(!flowdata.data.value) + { + reportOfflineNodeStatus(flowdata.data.line); + } + else + { + reportOnlineNodeStatus(flowdata.data.line); + } + } + + } + else if(cmd == "rotary_switch_state") + { + //state was changed + if(rotary_switch_state != flowdata.data.value) + { + if(rotary_switch_state == "Off") + { + //vyreportovat vsetky svietdla + reportOfflineNodeStatus(); + } + else reportOnlineNodeStatus(); + + } + + rotary_switch_state = flowdata.data.value; + } + else if(cmd == "lux_sensor") + { + lux_sensor = parseInt(flowdata.data.value); + + //process profiles + turnOnOffLinesAccordingToLuxSensor(lux_sensor); + } + 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; + + 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(dataChanged) { + + 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}, "", instanceSendTo.tb, instance, "circuit_breaker"); + else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", {line: line}, "", instanceSendTo.tb, instance, "circuit_breaker"); + + //report status liniu + let values = { + "status": status + }; + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + //instance.send(instanceSendTo.tb, dataToTb); + tbHandler.sendToTb(dataToTb, instance); + + //current value + if(value == "Off") + { + //vyreportovat vsetky svietdla na linii + reportOfflineNodeStatus(line); + } + else reportOnlineNodeStatus(line); + } + + } + } + else{ + logger.debug("undefined cmd", cmd); + } + } + } + + return; + } + + //data from worksys + if(flowdata.data.hasOwnProperty("topic")) + { + + let data = flowdata.data.content.data; + + let command = data.params.command; + let method = data.method; + let profile = data.params.payload; + if(profile == undefined) profile = ""; + let entity = data.params.entities[0]; + let entity_type = entity.entity_type; + let tbname = entity.tb_name; + + instance.send(instanceSendTo.debug, flowdata.data); + logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method); + logger.debug("----------------------------"); + + if(entity_type == "street_luminaire") + { + if(method == "set_command") + { + + //let command = data.params.command; + let value = data.params.payload.value; + + if(command == "dimming") + { + + let nodeWasFound = false; + let keys = Object.keys(nodesData); + + //logger.debug("-----", keys); + + 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(priorityTypes.high_priority); + + 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 = priorityTypes.high_priority; + params.info = 'set dimming from platform'; + //params.debug = true; + + //ak linia je + + //debug(params); + logger.debug("dimming", params); + + tasks.push(params); + + setTimeout(function(){ + + //spustime o 4 sekundy neskor, s prioritou priorityTypes.high_priority + //a pridame aj vyreportovanie dimmingu + { + let params = getParams(priorityTypes.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 = priorityTypes.high_priority; + params.info = 'read dimming (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - vykon + { + let params = getParams(priorityTypes.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 76; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = priorityTypes.high_priority; + params.info = 'read Input Power (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - prud svietidla + { + let params = getParams(priorityTypes.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 75; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = priorityTypes.high_priority; + params.info = 'read Input Current (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - power faktor - ucinnik + { + let params = getParams(priorityTypes.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 77; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = priorityTypes.high_priority; + params.info = 'read power factor - Cos phi (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + },4000); + + + nodeWasFound = true; + + break; + } + } + + if(!nodeWasFound) + { + logger.debug("set dimming from platform", "unable to find tbname", tbname); + } + } + else + { + instance.send(instanceSendTo.debug, "undefined command " + command); + logger.debug("undefined command", command); + } + + return; + + } + else if(method == "set_profile") + { + //nastav profil nodu + logger.debug("-->set_profile for node", data.params); + logger.debug("------profile data", profile); + //instance.send(instanceSendTo.debug, "set_profile" + command); + + let keys = Object.keys(nodesData); + for(let i = 0; i < keys.length; i++) + { + let node = keys[i]; + if(tbname == nodesData[node].tbname.trim()) + { + + 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"); + + //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, instanceSendTo.tb, instance, null ); + sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", {node: node}, profile, instanceSendTo.tb, instance ); + + nodesData[node].processed = false; + nodesData[node].profile = profile; + + let line = nodesData[node].line; + processNodeProfile(node); + + }); + }); + } + } + } + else + { + + instance.send(instanceSendTo.debug, "unknown method " + method); + logger.debug("unknown method", method); + + return; + } + + } + + //nastav profil linie z platformy + 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") + { + + 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++) + { + let line = keys[i]; + if(tbname == relaysData[line].tbname) + { + //zmazeme tasky + 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) { + + //update profile + logger.debug("worksys - update relay profile done:", profile); + instance.send(instanceSendTo.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, instanceSendTo.tb, instance ); + + }); + }); + + break; + } + } + } + else if(method == "set_command") + { + let value = data.params.payload.value; + + 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)); + + 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"); + } + + } + else + { + instance.send(instanceSendTo.debug, "undefined method " + method); + logger.debug("undefined method", method); + } + + return; + + } + else{ + instance.send(instanceSendTo.debug, "UNKNOW entity_type " + entity_type); + logger.debug("UNKNOW entity_type", entity_type); + } + + return; + } + + //terminal + if(!rsPort.isOpen) await rsPort.open(); + + let params = flowdata.data.body; + if(params == undefined) + { + //logger.debug("CMD manager flowdata.data.body is undefined"); + return; + } + + params.priority = priorityTypes.terminal; + params.type = "cmd-terminal"; + params.tbname = ""; + params.timestamp = priorityTypes.terminal; + params.addMinutesToTimestamp = 0;// do not repeat task!!! + params.debug = true; + + let timestamp = Date.now(); + params.refFlowdataKey = timestamp; + //params.refFlowdata = flowdata; + //refFlowdata = flowdata; + + //console.log("flowdata", flowdata); + + cleanUpRefFlowdataObj(); + + refFlowdataObj[ timestamp ] = flowdata; + + //fix + //params.address = params.adress; + logger.debug("received from terminal", params); + logger.debug("date/time:", new Date()); + logger.debug("tasks length:", tasks.length); + + //tasks = []; + + //add to tasks + tasks.push(params); + + } + } + }) + +} // 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 calculateDuskDown(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; + +} + + + + diff --git a/flow/designer.json b/flow/designer.json index cc01fc6..9fe9d06 100644 --- a/flow/designer.json +++ b/flow/designer.json @@ -20,68 +20,13 @@ } ], "components": [ - { - "id": "1611938185451", - "component": "modbus_citysys", - "tab": "1611921777196", - "name": "Modbus_citysys", - "x": 159.5, - "y": 164.5, - "connections": { - "0": [ - { - "index": "0", - "id": "1611951142547" - } - ], - "1": [ - { - "index": "0", - "id": "1611938192035" - } - ], - "2": [ - { - "index": "0", - "id": "1612772119611" - }, - { - "index": "0", - "id": "1611938192035" - } - ], - "3": [ - { - "index": "0", - "id": "1621340721628" - }, - { - "index": "0", - "id": "1611938192035" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Running", - "color": "green" - }, - "options": { - "edge": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV" - }, - "color": "#2134B0", - "notes": "" - }, { "id": "1611938192035", "component": "debug", "tab": "1611921777196", - "name": "Debug", - "x": 566.5, - "y": 168.5, + "name": "modbus_ddebug", + "x": 400.5, + "y": 121.5, "connections": {}, "disabledio": { "input": [], @@ -104,8 +49,8 @@ "component": "debug", "tab": "1611921777196", "name": "ERROR", - "x": 562, - "y": 54, + "x": 404, + "y": 29, "connections": {}, "disabledio": { "input": [], @@ -127,20 +72,20 @@ "id": "1612772119611", "component": "virtualwireout", "tab": "1611921777196", - "name": "tb-demo-push", - "x": 625.75, - "y": 324.5, + "name": "tb-push", + "x": 399.75, + "y": 211.5, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "tb-demo-push", + "text": "tb-push", "color": "gray" }, "options": { - "wirename": "tb-demo-push" + "wirename": "tb-push" }, "color": "#303E4D", "notes": "" @@ -150,8 +95,8 @@ "component": "wsmqttpublish", "tab": "1612772287426", "name": "WS MQTT publish", - "x": 380.75, - "y": 264, + "x": 311.75, + "y": 268, "connections": { "0": [ { @@ -189,8 +134,8 @@ "color": "green" }, "options": { - "username": "xmRd6RJxW53WZe4vMFLU", - "clientid": "showroom_test_panel_led", + "username": "", + "clientid": "", "port": "1883", "host": "" }, @@ -201,7 +146,7 @@ "id": "1612778461252", "component": "virtualwirein", "tab": "1612772287426", - "name": "tb-demo-push", + "name": "tb-push", "x": 68.75, "y": 289, "connections": { @@ -213,14 +158,6 @@ { "index": "0", "id": "1612783322136" - }, - { - "index": "0", - "id": "1656081515468" - }, - { - "index": "0", - "id": "1656420898232" } ] }, @@ -229,11 +166,11 @@ "output": [] }, "state": { - "text": "tb-demo-push", + "text": "tb-push", "color": "gray" }, "options": { - "wirename": "tb-demo-push" + "wirename": "tb-push" }, "color": "#303E4D", "notes": "" @@ -243,8 +180,8 @@ "component": "debug", "tab": "1612772287426", "name": "to TB", - "x": 383.75, - "y": 167, + "x": 317.75, + "y": 174, "connections": {}, "disabledio": { "input": [ @@ -289,8 +226,8 @@ "component": "debug", "tab": "1612772287426", "name": "errors from MQTT Broker", - "x": 660, - "y": 126, + "x": 610, + "y": 131, "connections": {}, "disabledio": { "input": [ @@ -315,8 +252,8 @@ "component": "debug", "tab": "1615551125555", "name": "Debug", - "x": 806, - "y": 9, + "x": 763, + "y": 123, "connections": {}, "disabledio": { "input": [ @@ -340,20 +277,20 @@ "id": "1615566865233", "component": "virtualwireout", "tab": "1615551125555", - "name": "tb-demo-push", - "x": 802, - "y": 101, + "name": "tb-push", + "x": 761, + "y": 216, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "tb-demo-push", + "text": "tb-push", "color": "gray" }, "options": { - "wirename": "tb-demo-push" + "wirename": "tb-push" }, "color": "#303E4D", "notes": "" @@ -362,9 +299,9 @@ "id": "1615798582262", "component": "debug", "tab": "1615551125555", - "name": "data to TB", - "x": 802, - "y": 190, + "name": "CMD_debug", + "x": 758, + "y": 301, "connections": {}, "disabledio": { "input": [ @@ -389,8 +326,8 @@ "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 660.8833312988281, - "y": 527.3500061035156, + "x": 398.8833312988281, + "y": 477.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -415,8 +352,8 @@ "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 649.8833312988281, - "y": 633.3500061035156, + "x": 406.8833312988281, + "y": 567.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -440,79 +377,40 @@ "id": "1615809595184", "component": "virtualwireout", "tab": "1611921777196", - "name": "tb-demo-push", - "x": 403.8833312988281, - "y": 663.25, + "name": "tb-push", + "x": 404.8833312988281, + "y": 653.25, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "tb-demo-push", + "text": "tb-push", "color": "gray" }, "options": { - "wirename": "tb-demo-push" + "wirename": "tb-push" }, "color": "#303E4D", "notes": "" }, - { - "id": "1615809105191", - "component": "gettemperature", - "tab": "1611921777196", - "name": "Get RVO temperature", - "x": 124.88333129882812, - "y": 488.3500061035156, - "connections": { - "0": [ - { - "index": "0", - "id": "1615802995322" - } - ], - "1": [ - { - "index": "0", - "id": "1615809128443" - }, - { - "index": "0", - "id": "1615809595184" - } - ], - "2": [ - { - "index": "0", - "id": "1621340721628" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#5CB36D", - "notes": "" - }, { "id": "1616165795916", "component": "httproute", "tab": "1615551125555", "name": "POST /terminal", - "x": 72, - "y": 314, + "x": 110, + "y": 508, "connections": { "0": [ { "index": "0", "id": "1619515097737" + }, + { + "index": "0", + "id": "1684060205000" } ] }, @@ -548,8 +446,8 @@ "component": "httpresponse", "tab": "1615551125555", "name": "HTTP Response", - "x": 800, - "y": 273, + "x": 759, + "y": 377, "connections": {}, "disabledio": { "input": [], @@ -569,9 +467,9 @@ "id": "1617104731852", "component": "debug", "tab": "1615551125555", - "name": "Debug", - "x": 807, - "y": 545, + "name": "DIDO_Debug", + "x": 743, + "y": 839, "connections": {}, "disabledio": { "input": [ @@ -596,13 +494,13 @@ "component": "trigger", "tab": "1615551125555", "name": "turnOff line", - "x": 74, - "y": 507, + "x": 75, + "y": 1033, "connections": { "0": [ { - "index": "0", - "id": "1618232536546" + "index": "1", + "id": "1699963668903" } ] }, @@ -615,7 +513,7 @@ "color": "gray" }, "options": { - "data": "{line:2, command: \"turnOff\", force: true}", + "data": "{line: 3, command: \"turnOff\", force: true}", "datatype": "object" }, "color": "#F6BB42", @@ -625,20 +523,20 @@ "id": "1617115013095", "component": "virtualwireout", "tab": "1615551125555", - "name": "tb-demo-push", - "x": 794, - "y": 637, + "name": "tb-push", + "x": 751, + "y": 940, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "tb-demo-push", + "text": "tb-push", "color": "gray" }, "options": { - "wirename": "tb-demo-push" + "wirename": "tb-push" }, "color": "#303E4D", "notes": "" @@ -648,8 +546,8 @@ "component": "debug", "tab": "1615551125555", "name": "Debug", - "x": 703, - "y": 846, + "x": 628, + "y": 1246, "connections": {}, "disabledio": { "input": [], @@ -672,8 +570,8 @@ "component": "trigger", "tab": "1615551125555", "name": "start import", - "x": 312, - "y": 870, + "x": 258, + "y": 1254, "connections": { "0": [ { @@ -702,8 +600,8 @@ "component": "csv_import", "tab": "1615551125555", "name": "CsvImport", - "x": 508, - "y": 809, + "x": 437, + "y": 1235, "connections": { "0": [ { @@ -731,8 +629,8 @@ "component": "comment", "tab": "1615551125555", "name": "import data from csv", - "x": 485, - "y": 748, + "x": 424, + "y": 1168, "connections": {}, "disabledio": { "input": [], @@ -751,8 +649,8 @@ "component": "trigger", "tab": "1615551125555", "name": "update profile / node", - "x": 77, - "y": 57, + "x": 119, + "y": 130, "connections": { "0": [ { @@ -776,54 +674,13 @@ "color": "#F6BB42", "notes": "" }, - { - "id": "1618232536546", - "component": "di_do_controller", - "tab": "1615551125555", - "name": "DI_DO_Controller", - "x": 450, - "y": 547, - "connections": { - "0": [ - { - "index": "0", - "id": "1617104731852" - } - ], - "1": [ - { - "index": "0", - "id": "1617115013095" - } - ], - "2": [ - { - "index": "0", - "id": "1618393583970" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "edge": "R3JjOWdylwgNLzxVab7NEBkZ2vG64rq8PEB5QmDo" - }, - "color": "#2134B0", - "notes": "" - }, { "id": "1618235171399", "component": "trigger", "tab": "1615551125555", - "name": "tun tasks", - "x": 80, - "y": 134, + "name": "run tasks", + "x": 122, + "y": 206, "connections": { "0": [ { @@ -851,8 +708,8 @@ "component": "debug", "tab": "1612772287426", "name": "wsmqtt-exit1", - "x": 679.8833312988281, - "y": 218, + "x": 610.8833312988281, + "y": 219, "connections": {}, "disabledio": { "input": [], @@ -875,8 +732,8 @@ "component": "debug", "tab": "1612772287426", "name": "wsmqtt-exit2", - "x": 753.8833312988281, - "y": 391, + "x": 611.8833312988281, + "y": 394, "connections": {}, "disabledio": { "input": [ @@ -900,20 +757,20 @@ "id": "1618393583970", "component": "virtualwireout", "tab": "1615551125555", - "name": "platform-rpc-call", - "x": 796.8833312988281, - "y": 725, + "name": "to-cmd-manager", + "x": 744.8833312988281, + "y": 1032, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "platform-rpc-call", + "text": "from-dido-controller", "color": "gray" }, "options": { - "wirename": "platform-rpc-call" + "wirename": "from-dido-controller" }, "color": "#303E4D", "notes": "" @@ -923,8 +780,8 @@ "component": "virtualwirein", "tab": "1615551125555", "name": "platform-rpc-call", - "x": 74.88333129882812, - "y": 222, + "x": 115.88333129882812, + "y": 316, "connections": { "0": [ { @@ -951,18 +808,18 @@ "id": "1618393759854", "component": "virtualwirein", "tab": "1615551125555", - "name": "di_do_controller-in", - "x": 72.88333129882812, - "y": 657, + "name": "cmd_to_dido", + "x": 78.88333129882812, + "y": 864, "connections": { "0": [ { "index": "0", - "id": "1618232536546" + "id": "1683664161036" }, { - "index": "0", - "id": "1683922207976" + "index": "1", + "id": "1699963668903" } ] }, @@ -971,11 +828,11 @@ "output": [] }, "state": { - "text": "di_do_controller-in", + "text": "cmd_to_dido", "color": "gray" }, "options": { - "wirename": "di_do_controller-in" + "wirename": "cmd_to_dido" }, "color": "#303E4D", "notes": "" @@ -984,20 +841,20 @@ "id": "1618393827655", "component": "virtualwireout", "tab": "1615551125555", - "name": "di_do_controller-in", - "x": 798.8833312988281, - "y": 377, + "name": "cmd_to_dido", + "x": 756.8833312988281, + "y": 477, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "di_do_controller-in", + "text": "cmd_to_dido", "color": "gray" }, "options": { - "wirename": "di_do_controller-in" + "wirename": "cmd_to_dido" }, "color": "#303E4D", "notes": "" @@ -1007,7 +864,7 @@ "component": "virtualwireout", "tab": "1612772287426", "name": "platform-rpc-call", - "x": 688.8833312988281, + "x": 611.8833312988281, "y": 307, "connections": {}, "disabledio": { @@ -1029,13 +886,13 @@ "component": "trigger", "tab": "1615551125555", "name": "turnOn line", - "x": 75, - "y": 568, + "x": 76, + "y": 947, "connections": { "0": [ { - "index": "0", - "id": "1618232536546" + "index": "1", + "id": "1699963668903" } ] }, @@ -1049,7 +906,7 @@ }, "options": { "datatype": "object", - "data": "{line: 3, command: \"turnOn\", force: true}" + "data": "{line: 1, command: \"turnOn\", force: true}" }, "color": "#F6BB42", "notes": "" @@ -1059,8 +916,8 @@ "component": "cmd_manager", "tab": "1615551125555", "name": "CMD Manager", - "x": 431, - "y": 150, + "x": 442, + "y": 290, "connections": { "0": [ { @@ -1114,13 +971,17 @@ "component": "httproute", "tab": "1615551125555", "name": "GET db", - "x": 70, - "y": 420, + "x": 104, + "y": 619, "connections": { "0": [ { "index": "0", "id": "1619515097737" + }, + { + "index": "0", + "id": "1684060205000" } ] }, @@ -1136,7 +997,7 @@ "timeout": 5, "cachepolicy": 0, "cacheexpire": "5 minutes", - "size": 100, + "size": 5, "url": "/db", "method": "GET", "name": "", @@ -1147,7 +1008,7 @@ ] }, "color": "#5D9CEC", - "notes": "### Configuration\n\n- __GET /db__\n- flags: \n- maximum request data length: __100 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", + "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", "cloning": false }, { @@ -1155,13 +1016,13 @@ "component": "trigger", "tab": "1615551125555", "name": "turnOnAlarm", - "x": 82, - "y": 755, + "x": 72, + "y": 1106, "connections": { "0": [ { - "index": "0", - "id": "1618232536546" + "index": "1", + "id": "1699963668903" } ] }, @@ -1185,13 +1046,13 @@ "component": "trigger", "tab": "1615551125555", "name": "turnOffAlarm", - "x": 88, - "y": 819, + "x": 71, + "y": 1179, "connections": { "0": [ { - "index": "0", - "id": "1618232536546" + "index": "1", + "id": "1699963668903" } ] }, @@ -1214,20 +1075,20 @@ "id": "1621340721628", "component": "virtualwireout", "tab": "1611921777196", - "name": "di_do_controller-in", - "x": 630, - "y": 422, + "name": "modbus_to_dido", + "x": 396, + "y": 390, "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "di_do_controller-in", + "text": "modbus_to_dido", "color": "gray" }, "options": { - "wirename": "di_do_controller-in" + "wirename": "modbus_to_dido" }, "color": "#303E4D", "notes": "" @@ -1259,7 +1120,7 @@ "timeout": 5, "cachepolicy": 0, "cacheexpire": "5 minutes", - "size": 500, + "size": 5, "url": "/db_connector", "method": "POST", "flags": [ @@ -1269,7 +1130,7 @@ ] }, "color": "#5D9CEC", - "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __500 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", + "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", "cloning": false }, { @@ -1326,8 +1187,8 @@ "component": "monitormemory", "tab": "1612772287426", "name": "RAM", - "x": 72.88333129882812, - "y": 674.5, + "x": 71.88333129882812, + "y": 629.5, "connections": { "0": [ { @@ -1341,12 +1202,12 @@ "output": [] }, "state": { - "text": "203.08 MB / 249 MB", + "text": "826.22 MB / 985.68 MB", "color": "gray" }, "options": { "enabled": true, - "interval": 20000 + "interval": 30000 }, "color": "#F6BB42", "notes": "" @@ -1356,8 +1217,8 @@ "component": "monitordisk", "tab": "1612772287426", "name": "disk", - "x": 78.88333129882812, - "y": 774.5, + "x": 72.88333129882812, + "y": 726.5, "connections": { "0": [ { @@ -1371,13 +1232,13 @@ "output": [] }, "state": { - "text": "5.89 GB / 7.22 GB", + "text": "5.85 GB / 7.26 GB", "color": "gray" }, "options": { "enabled": true, "path": "/", - "interval": 20000 + "interval": 30000 }, "color": "#F6BB42", "notes": "" @@ -1420,8 +1281,8 @@ "component": "virtualwireout", "tab": "1612772287426", "name": "send-to-services", - "x": 416.8833312988281, - "y": 690.5, + "x": 428.8833312988281, + "y": 622.5, "connections": {}, "disabledio": { "input": [], @@ -1442,8 +1303,8 @@ "component": "virtualwireout", "tab": "1612772287426", "name": "send-to-services", - "x": 776.8833312988281, - "y": 476.5, + "x": 612.8833312988281, + "y": 482.5, "connections": {}, "disabledio": { "input": [], @@ -1464,8 +1325,9 @@ "component": "httprequest", "tab": "1612772287426", "name": "http://192.168.252.2:8004/sentmessage", - "x": 633.8833312988281, - "y": 1047.7333374023438, + "reference": "", + "x": 439.8833312988281, + "y": 1096.7333374023438, "connections": { "0": [ { @@ -1495,8 +1357,8 @@ "component": "debug", "tab": "1612772287426", "name": "Debug", - "x": 350.75, - "y": 1021, + "x": 234.75, + "y": 1044, "connections": {}, "disabledio": { "input": [ @@ -1521,8 +1383,8 @@ "component": "code", "tab": "1612772287426", "name": "Code", - "x": 241, - "y": 592, + "x": 255, + "y": 532, "connections": { "0": [ { @@ -1556,8 +1418,8 @@ "component": "debug", "tab": "1612772287426", "name": "Debug", - "x": 436, - "y": 590, + "x": 430, + "y": 528, "connections": {}, "disabledio": { "input": [ @@ -1582,8 +1444,8 @@ "component": "code", "tab": "1612772287426", "name": "Code", - "x": 232, - "y": 673, + "x": 244, + "y": 628, "connections": { "0": [ { @@ -1617,8 +1479,8 @@ "component": "debug", "tab": "1612772287426", "name": "Debug", - "x": 413, - "y": 775, + "x": 431, + "y": 720, "connections": {}, "disabledio": { "input": [ @@ -1643,8 +1505,8 @@ "component": "code", "tab": "1612772287426", "name": "Code", - "x": 234, - "y": 766, + "x": 247, + "y": 722, "connections": { "0": [ { @@ -1678,8 +1540,8 @@ "component": "debug", "tab": "1612772287426", "name": "Debug", - "x": 411, - "y": 862, + "x": 434, + "y": 812, "connections": {}, "disabledio": { "input": [ @@ -1704,8 +1566,8 @@ "component": "debug", "tab": "1612772287426", "name": "Send info", - "x": 475, - "y": 1202, + "x": 438, + "y": 1205, "connections": {}, "disabledio": { "input": [ @@ -1731,7 +1593,7 @@ "tab": "1612772287426", "name": "Info sender", "x": 233, - "y": 1148, + "y": 1142, "connections": { "0": [ { @@ -1763,8 +1625,8 @@ "component": "debug", "tab": "1612772287426", "name": "Debug", - "x": 1008.8833312988281, - "y": 1047.5, + "x": 811.8833312988281, + "y": 1090.5, "connections": {}, "disabledio": { "input": [ @@ -1789,8 +1651,8 @@ "component": "virtualwireout", "tab": "1615551125555", "name": "send-to-services", - "x": 725, - "y": 456, + "x": 756, + "y": 568, "connections": {}, "disabledio": { "input": [], @@ -1811,8 +1673,8 @@ "component": "monitorconsumption", "tab": "1612772287426", "name": "CPU", - "x": 80, - "y": 588, + "x": 71, + "y": 535, "connections": { "0": [ { @@ -1826,7 +1688,7 @@ "output": [] }, "state": { - "text": "9% / 57.78 MB", + "text": "0.9% / 86.46 MB", "color": "gray" }, "options": { @@ -1835,56 +1697,25 @@ "monitorsize": true, "monitorconsumption": true, "enabled": true, - "interval": 5000 + "interval": 30000 }, "color": "#967ADC", "notes": "" }, { - "id": "1656081515468", - "component": "code", - "tab": "1612772287426", - "name": "send just example nodes data", - "x": 327.8833312988281, - "y": 432.8000030517578, - "connections": { - "0": [ - { - "index": "0", - "id": "1656420898232" - } - ] - }, + "id": "1683664161036", + "component": "debug", + "tab": "1615551125555", + "name": "CMDtoDIDO", + "x": 417, + "y": 858, + "connections": {}, "disabledio": { "input": [ 0 ], "output": [] }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "keepmessage": true, - "code": "//send(0, value);\n\nconst nodes = ['oGVzxNWP9lrjaQ7vKODQ7g51gqp62YZREmdw3XBM','Ymn9oleRxJ0vw17WzAyGwdyEBk4ObdMXj2VgpNLG']\n\nif(nodes.includes(Object.keys(value)[0]))\n{\n\tif(value[Object.keys(value)[0]][0].values.hasOwnProperty('dimming') || value[Object.keys(value)[0]][0].values.hasOwnProperty('status'))\n\t{\n\t\tsend(0, value);\n\t}\n}\n\nconst example = {\n \"vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V\": [\n {\n \"ts\": 1656081519502,\n \"values\": {\n \"statecode\": 2\n }\n }\n ]\n}", - "outputs": 1 - }, - "color": "#656D78", - "notes": "" - }, - { - "id": "1656081823357", - "component": "debug", - "tab": "1612772287426", - "name": "1 mqtt processor exit 1", - "x": 1191.8833312988281, - "y": 509.8000030517578, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, "state": { "text": "Enabled", "color": "gray" @@ -1898,132 +1729,97 @@ "notes": "" }, { - "id": "1656164263549", - "component": "trigger", - "tab": "1612772287426", - "name": "Trigger", - "x": 629.3500061035156, - "y": 625.3999938964844, + "id": "1683981346282", + "component": "virtualwirein", + "tab": "1615551125555", + "name": "from-dido-controller", + "x": 113, + "y": 423, "connections": { "0": [ { "index": "0", - "id": "1656420898232" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "{ \t\t \"vnmG4kJxaXWNBgMQq0D7Mz5e9oZzOAlr6LdR3w2V\": [ \t\t\t{ \t\t\t \"ts\": 1656420464663, \t\t\t \"values\": { \t\t\"status\":\"OK\"\t } \t\t\t} \t\t ] \t\t}", - "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1656420898232", - "component": "mqttprocessor", - "tab": "1612772287426", - "name": "MQTT processor", - "x": 953.75, - "y": 578, - "connections": { - "0": [ - { - "index": "0", - "id": "1656081823357" - } - ], - "2": [ - { - "index": "0", - "id": "1656505814026" + "id": "1619515097737" }, { "index": "0", - "id": "1656586224071" + "id": "1684055037116" } ] }, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Connected", - "color": "green" - }, - "options": { - "username": "", - "clientid": "", - "port": 1883, - "host": "192.168.252.3" - }, - "color": "#888600", - "notes": "" - }, - { - "id": "1656505814026", - "component": "debug", - "tab": "1612772287426", - "name": "mqttprocessor exit 2", - "x": 1181, - "y": 687, - "connections": {}, "disabledio": { "input": [], "output": [] }, "state": { - "text": "Enabled", + "text": "from-dido-controller", "color": "gray" }, "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1656586224071", - "component": "virtualwireout", - "tab": "1612772287426", - "name": "3rd party system platform-rpc-call", - "x": 1181, - "y": 600.75, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "platform-rpc-call", - "color": "gray" - }, - "options": { - "wirename": "platform-rpc-call" + "wirename": "from-dido-controller" }, "color": "#303E4D", "notes": "" }, { - "id": "1683922207976", + "id": "1684055037116", "component": "debug", "tab": "1615551125555", - "name": "to dido_controller", - "x": 450, - "y": 476, + "name": "from dido to cmd", + "x": 441, + "y": 461, + "connections": {}, + "disabledio": { + "input": [ + 0 + ], + "output": [] + }, + "state": { + "text": "Enabled", + "color": "gray" + }, + "options": { + "type": "data", + "repository": false, + "enabled": true + }, + "color": "#967ADC", + "notes": "" + }, + { + "id": "1684060205000", + "component": "debug", + "tab": "1615551125555", + "name": "HTTP routes", + "x": 441, + "y": 564, + "connections": {}, + "disabledio": { + "input": [ + 0 + ], + "output": [] + }, + "state": { + "text": "Enabled", + "color": "gray" + }, + "options": { + "type": "data", + "repository": false, + "enabled": true + }, + "color": "#967ADC", + "notes": "" + }, + { + "id": "1684179110403", + "component": "debug", + "tab": "1611921777196", + "name": "MDBToDido", + "x": 402, + "y": 300, "connections": {}, "disabledio": { "input": [], @@ -2042,87 +1838,33 @@ "notes": "" }, { - "id": "1690972387040", - "component": "trigger", - "tab": "1612772287426", - "name": "Trigger", - "x": 73, - "y": 421, + "id": "1699963668903", + "component": "dido_controller", + "tab": "1615551125555", + "name": "DIDO_Controller", + "x": 406, + "y": 940, "connections": { "0": [ { "index": "0", - "id": "1612776786008" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "{ \"9YkRpoB2vVa0mKqEO8ZrOw8jW43eXnJML6GxzbwQ\": [ { \"ts\": 1690972374805, \"values\": { \"status\": \"OK\" } } ] }" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1691063647317", - "component": "trigger", - "tab": "1612772287426", - "name": "Trigger 650 ver4", - "x": 71, - "y": 497, - "connections": { - "0": [ - { - "index": "0", - "id": "1612776786008" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "{ \"GjQobgOK0n2YqBZmVDVzQGDR9ep6EXA1ka3vzlP7\": [ { \"ts\": 1690972374805, \"values\": { \"status\": \"OK\" } } ] }" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1702560071662", - "component": "mqttlistener", - "tab": "1612772287426", - "name": "MQTT listener", - "x": 244.88333129882812, - "y": 1397.433349609375, - "connections": { - "0": [ - { - "index": "0", - "id": "1702560098149" + "id": "1617104731852" } ], "1": [ { "index": "0", - "id": "1702560098149" + "id": "1617104731852" + }, + { + "index": "0", + "id": "1617115013095" } ], "2": [ { "index": "0", - "id": "1702560098149" + "id": "1618393583970" } ] }, @@ -2131,30 +1873,62 @@ "output": [] }, "state": { - "text": "Disconnected", - "color": "red" + "text": "", + "color": "gray" }, "options": { - "host": "192.168.252.2", - "port": "3883", - "clientid": "", - "username": "" + "edge": "undefined" }, - "color": "#888600", + "color": "#2134B0", "notes": "" }, { - "id": "1702560098149", - "component": "debug", - "tab": "1612772287426", - "name": "Debug", - "x": 471.8833312988281, - "y": 1412.433349609375, - "connections": {}, + "id": "1699964678894", + "component": "virtualwirein", + "tab": "1615551125555", + "name": "modbus_to_dido", + "x": 83, + "y": 775, + "connections": { + "0": [ + { + "index": "0", + "id": "1699963668903" + }, + { + "index": "0", + "id": "1699964793925" + } + ] + }, "disabledio": { "input": [], "output": [] }, + "state": { + "text": "modbus_to_dido", + "color": "gray" + }, + "options": { + "wirename": "modbus_to_dido" + }, + "color": "#303E4D", + "notes": "" + }, + { + "id": "1699964793925", + "component": "debug", + "tab": "1615551125555", + "name": "modbusToDido", + "x": 415, + "y": 765, + "connections": {}, + "disabledio": { + "input": [ + 0 + ], + "output": [] + }, "state": { "text": "Enabled", "color": "gray" @@ -2166,6 +1940,96 @@ }, "color": "#967ADC", "notes": "" + }, + { + "id": "1699965957410", + "component": "modbus_reader", + "tab": "1611921777196", + "name": "Modbus reader", + "x": 102, + "y": 175, + "connections": { + "0": [ + { + "index": "0", + "id": "1611951142547" + } + ], + "1": [ + { + "index": "0", + "id": "1621340721628" + }, + { + "index": "0", + "id": "1684179110403" + } + ], + "2": [ + { + "index": "0", + "id": "1621340721628" + }, + { + "index": "0", + "id": "1684179110403" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "", + "color": "gray" + }, + "options": {}, + "color": "#2134B0", + "notes": "" + }, + { + "id": "1700411878636", + "component": "thermometer", + "tab": "1611921777196", + "name": "Thermometer", + "x": 94.75, + "y": 414, + "connections": { + "0": [ + { + "index": "0", + "id": "1615802995322" + } + ], + "1": [ + { + "index": "0", + "id": "1615809595184" + }, + { + "index": "0", + "id": "1615809128443" + } + ], + "2": [ + { + "index": "0", + "id": "1621340721628" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "", + "color": "gray" + }, + "options": {}, + "color": "#5CB36D", + "notes": "" } ], "version": 615 diff --git a/flow/designer_deploy.json b/flow/designer_deploy.json deleted file mode 100644 index e6242ce..0000000 --- a/flow/designer_deploy.json +++ /dev/null @@ -1,1516 +0,0 @@ -{ - "tabs": [ - { - "name": "MAIN PUSH", - "linker": "main-push", - "id": "1612772287426", - "index": 0 - }, - { - "name": "CMD manager", - "linker": "cmd-manager", - "id": "1615551125555", - "index": 1 - }, - { - "name": "Devices", - "linker": "devices", - "id": "1611921777196", - "index": 2 - } - ], - "components": [ - { - "id": "1611938185451", - "component": "modbus_citysys", - "tab": "1611921777196", - "name": "Modbus_citysys", - "x": 159.5, - "y": 164.5, - "connections": { - "0": [ - { - "index": "0", - "id": "1611951142547" - } - ], - "1": [ - { - "index": "0", - "id": "1611938192035" - } - ], - "2": [ - { - "index": "0", - "id": "1612772119611" - }, - { - "index": "0", - "id": "1611938192035" - } - ], - "3": [ - { - "index": "0", - "id": "1621340721628" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Running", - "color": "green" - }, - "options": { - "edge": "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV" - }, - "color": "#2134B0", - "notes": "" - }, - { - "id": "1611938192035", - "component": "debug", - "tab": "1611921777196", - "name": "Debug", - "x": 566.5, - "y": 168.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": 562, - "y": 54, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#DA4453", - "notes": "" - }, - { - "id": "1612772119611", - "component": "virtualwireout", - "tab": "1611921777196", - "name": "tb-demo-push", - "x": 625.75, - "y": 324.5, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-demo-push", - "color": "gray" - }, - "options": { - "wirename": "tb-demo-push" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1612776786008", - "component": "wsmqttpublish", - "tab": "1612772287426", - "name": "WS MQTT publish", - "x": 384.75, - "y": 247, - "connections": { - "0": [ - { - "index": "0", - "id": "1615551060773" - } - ], - "1": [ - { - "index": "0", - "id": "1618300858252" - }, - { - "index": "0", - "id": "1618558465485" - } - ], - "2": [ - { - "index": "0", - "id": "1613568918462" - }, - { - "index": "0", - "id": "1618300863816" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Connected", - "color": "green" - }, - "options": { - "username": "", - "clientid": "", - "port": "1883", - "host": "" - }, - "color": "#888600", - "notes": "" - }, - { - "id": "1612778461252", - "component": "virtualwirein", - "tab": "1612772287426", - "name": "tb-demo-push", - "x": 68.75, - "y": 269, - "connections": { - "0": [ - { - "index": "0", - "id": "1612776786008" - }, - { - "index": "0", - "id": "1612783322136" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-demo-push", - "color": "gray" - }, - "options": { - "wirename": "tb-demo-push" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1612783322136", - "component": "debug", - "tab": "1612772287426", - "name": "Debug", - "x": 426.75, - "y": 140, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1613568918462", - "component": "nosql", - "tab": "1612772287426", - "name": "Insert data to DB", - "x": 653.8833312988281, - "y": 460, - "connections": { - "0": [ - { - "index": "0", - "id": "1613568955702" - } - ], - "1": [ - { - "index": "0", - "id": "1613568983491" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "method": "insert", - "collection": "tbdata", - "addid": true - }, - "color": "#D770AD", - "notes": "" - }, - { - "id": "1613568955702", - "component": "debug", - "tab": "1612772287426", - "name": "Insert NOSQL", - "x": 906.8833312988281, - "y": 404, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1613568983491", - "component": "debug", - "tab": "1612772287426", - "name": "Inserted data NOSQL", - "x": 907.8833312988281, - "y": 501, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1613569046792", - "component": "httproute", - "tab": "1612772287426", - "name": "GET /tbdata", - "x": 36.883331298828125, - "y": 526, - "connections": { - "0": [ - { - "index": "0", - "id": "1613569068475" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Listening", - "color": "green" - }, - "options": { - "timeout": 5, - "cachepolicy": 0, - "cacheexpire": "5 minutes", - "size": 5, - "url": "/tbdata", - "method": "GET", - "name": "", - "flags": [ - "id:1613569046792", - "get", - 5000 - ] - }, - "color": "#5D9CEC", - "notes": "### Configuration\n\n- __GET /tbdata__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", - "cloning": false - }, - { - "id": "1613569068475", - "component": "nosql", - "tab": "1612772287426", - "name": "GET data from db", - "x": 248.88333129882812, - "y": 629, - "connections": { - "0": [ - { - "index": "0", - "id": "1613569129780" - }, - { - "index": "0", - "id": "1613574834147" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "method": "query", - "collection": "tbdata" - }, - "color": "#D770AD", - "notes": "" - }, - { - "id": "1613569129780", - "component": "code", - "tab": "1612772287426", - "name": "Code", - "x": 522.8833312988281, - "y": 702, - "connections": { - "0": [ - { - "index": "0", - "id": "1613569234477" - } - ], - "1": [ - { - "index": "0", - "id": "1613569202286" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "keepmessage": true, - "code": "//send(1, value);\n//value[\"response\"].map( item => {\n //if (typeof item.id !== \"undefined\" ){\n\t//send(0, {id:item.id});\n //}\n//})\n\nsend(1, value);\nlet reversed = value[\"response\"].reverse();\nreversed.map( item => {\n\tif (item.id !== undefined) {\n\t\tsend(0, {id: item.id});\n\t}\n})", - "outputs": 2 - }, - "color": "#656D78", - "notes": "", - "output": 2 - }, - { - "id": "1613569202286", - "component": "debug", - "tab": "1612772287426", - "name": "Data from DB", - "x": 717.8833312988281, - "y": 773, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1613569234477", - "component": "nosql", - "tab": "1612772287426", - "name": "Remove data from DB", - "x": 715.8833312988281, - "y": 650, - "connections": { - "0": [ - { - "index": "0", - "id": "1613569269806" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "method": "remove", - "collection": "tbdata" - }, - "color": "#D770AD", - "notes": "" - }, - { - "id": "1613569269806", - "component": "debug", - "tab": "1612772287426", - "name": "Removed data", - "x": 1006.8833312988281, - "y": 602, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1613574834147", - "component": "httpresponse", - "tab": "1612772287426", - "name": "HTTP Response", - "x": 498.8833312988281, - "y": 569, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "0.29 sec.", - "color": "gray" - }, - "options": { - "datatype": "json" - }, - "color": "#5D9CEC", - "notes": "" - }, - { - "id": "1613576617722", - "component": "comment", - "tab": "1612772287426", - "name": "In case broker is not ready, we save data to database, and when connected, we resend data", - "x": 72.88333129882812, - "y": 12, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#704cff", - "notes": "" - }, - { - "id": "1615551060773", - "component": "debug", - "tab": "1612772287426", - "name": "errors from MQTT Broker", - "x": 660, - "y": 106, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#DA4453", - "notes": "" - }, - { - "id": "1615563373927", - "component": "debug", - "tab": "1615551125555", - "name": "Debug", - "x": 803, - "y": 27, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#DA4453", - "notes": "" - }, - { - "id": "1615566865233", - "component": "virtualwireout", - "tab": "1615551125555", - "name": "tb-demo-push", - "x": 802, - "y": 101, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-demo-push", - "color": "gray" - }, - "options": { - "wirename": "tb-demo-push" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1615798582262", - "component": "debug", - "tab": "1615551125555", - "name": "data to TB", - "x": 802, - "y": 190, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1615802995322", - "component": "debug", - "tab": "1611921777196", - "name": "Debug", - "x": 660.8833312988281, - "y": 527.3500061035156, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1615809128443", - "component": "debug", - "tab": "1611921777196", - "name": "Debug", - "x": 649.8833312988281, - "y": 633.3500061035156, - "connections": {}, - "disabledio": { - "input": [ - 0 - ], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1615809595184", - "component": "virtualwireout", - "tab": "1611921777196", - "name": "tb-demo-push", - "x": 403.8833312988281, - "y": 663.25, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-demo-push", - "color": "gray" - }, - "options": { - "wirename": "tb-demo-push" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1615809105191", - "component": "gettemperature", - "tab": "1611921777196", - "name": "Get RVO temperature", - "x": 124.88333129882812, - "y": 488.3500061035156, - "connections": { - "0": [ - { - "index": "0", - "id": "1615802995322" - } - ], - "1": [ - { - "index": "0", - "id": "1615809128443" - }, - { - "index": "0", - "id": "1615809595184" - } - ], - "2": [ - { - "index": "0", - "id": "1621340721628" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#5CB36D", - "notes": "" - }, - { - "id": "1616165795916", - "component": "httproute", - "tab": "1615551125555", - "name": "POST /terminal", - "x": 72, - "y": 314, - "connections": { - "0": [ - { - "index": "0", - "id": "1619515097737" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Listening", - "color": "green" - }, - "options": { - "timeout": 5, - "cachepolicy": 0, - "cacheexpire": "5 minutes", - "size": 5, - "url": "/terminal", - "method": "POST", - "name": "", - "flags": [ - "id:1616165795916", - "post", - 5000 - ] - }, - "color": "#5D9CEC", - "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", - "cloning": false - }, - { - "id": "1616165824813", - "component": "httpresponse", - "tab": "1615551125555", - "name": "HTTP Response", - "x": 800, - "y": 273, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "datatype": "json" - }, - "color": "#5D9CEC", - "notes": "" - }, - { - "id": "1617104731852", - "component": "debug", - "tab": "1615551125555", - "name": "Debug", - "x": 803, - "y": 499, - "connections": {}, - "disabledio": { - "input": [], - "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": 74, - "y": 507, - "connections": { - "0": [ - { - "index": "0", - "id": "1618232536546" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "datatype": "object", - "data": "{line: 1, command: \"turnOff\"}" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1617115013095", - "component": "virtualwireout", - "tab": "1615551125555", - "name": "tb-demo-push", - "x": 797, - "y": 596, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-demo-push", - "color": "gray" - }, - "options": { - "wirename": "tb-demo-push" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1617178324650", - "component": "debug", - "tab": "1615551125555", - "name": "Debug", - "x": 703, - "y": 846, - "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": 300, - "y": 791, - "connections": { - "0": [ - { - "index": "0", - "id": "1617180390661" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "{table: \"nodesx\", startFrom: 1, delimiter: \";\", uniqueColumn: \"node\", path: \"flow/audit_rvo14_lampy.csv\", mapImport: {1: \"node\",\t3: \"tbname\", 2: \"line\"}}", - "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1617180390661", - "component": "csv_import", - "tab": "1615551125555", - "name": "CsvImport", - "x": 508, - "y": 809, - "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": 485, - "y": 748, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#704cff", - "notes": "" - }, - { - "id": "1617284749681", - "component": "trigger", - "tab": "1615551125555", - "name": "update profile / node", - "x": 77, - "y": 57, - "connections": { - "0": [ - { - "index": "0", - "id": "1619515097737" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "profile_nodes", - "datatype": "string" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1618232536546", - "component": "di_do_controller", - "tab": "1615551125555", - "name": "DI_DO_Controller", - "x": 450, - "y": 547, - "connections": { - "0": [ - { - "index": "0", - "id": "1617104731852" - } - ], - "1": [ - { - "index": "0", - "id": "1617115013095" - } - ], - "2": [ - { - "index": "0", - "id": "1618393583970" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "edge": "R3JjOWdylwgNLzxVab7NEBkZ2vG64rq8PEB5QmDo" - }, - "color": "#2134B0", - "notes": "" - }, - { - "id": "1618235171399", - "component": "trigger", - "tab": "1615551125555", - "name": "tun tasks", - "x": 80, - "y": 134, - "connections": { - "0": [ - { - "index": "0", - "id": "1619515097737" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "run" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1618300858252", - "component": "debug", - "tab": "1612772287426", - "name": "wsmqtt-exit1", - "x": 657.8833312988281, - "y": 198, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1618300863816", - "component": "debug", - "tab": "1612772287426", - "name": "wsmqtt-exit2", - "x": 654.8833312988281, - "y": 384, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Enabled", - "color": "gray" - }, - "options": { - "type": "data", - "repository": false, - "enabled": true - }, - "color": "#967ADC", - "notes": "" - }, - { - "id": "1618393583970", - "component": "virtualwireout", - "tab": "1615551125555", - "name": "platform-rpc-call", - "x": 802.8833312988281, - "y": 687, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "platform-rpc-call", - "color": "gray" - }, - "options": { - "wirename": "platform-rpc-call" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1618393674428", - "component": "virtualwirein", - "tab": "1615551125555", - "name": "platform-rpc-call", - "x": 78.88333129882812, - "y": 221, - "connections": { - "0": [ - { - "index": "0", - "id": "1619515097737" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "platform-rpc-call", - "color": "gray" - }, - "options": { - "wirename": "platform-rpc-call" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1618393759854", - "component": "virtualwirein", - "tab": "1615551125555", - "name": "di_do_controller-in", - "x": 72.88333129882812, - "y": 657, - "connections": { - "0": [ - { - "index": "0", - "id": "1618232536546" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "di_do_controller-in", - "color": "gray" - }, - "options": { - "wirename": "di_do_controller-in" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1618393827655", - "component": "virtualwireout", - "tab": "1615551125555", - "name": "di_do_controller-in", - "x": 798.8833312988281, - "y": 377, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "di_do_controller-in", - "color": "gray" - }, - "options": { - "wirename": "di_do_controller-in" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1618558465485", - "component": "virtualwireout", - "tab": "1612772287426", - "name": "platform-rpc-call", - "x": 652.8833312988281, - "y": 290, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "platform-rpc-call", - "color": "gray" - }, - "options": { - "wirename": "platform-rpc-call" - }, - "color": "#303E4D", - "notes": "" - }, - { - "id": "1618572059773", - "component": "trigger", - "tab": "1615551125555", - "name": "turnOn line", - "x": 75, - "y": 568, - "connections": { - "0": [ - { - "index": "0", - "id": "1618232536546" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "data": "{line: 1, command: \"turnOn\"}", - "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1619515097737", - "component": "cmd_manager", - "tab": "1615551125555", - "name": "CMD Manager", - "x": 431, - "y": 150, - "connections": { - "0": [ - { - "index": "0", - "id": "1615563373927" - } - ], - "1": [ - { - "index": "0", - "id": "1615566865233" - }, - { - "index": "0", - "id": "1615798582262" - } - ], - "2": [ - { - "index": "0", - "id": "1616165824813" - } - ], - "3": [ - { - "index": "0", - "id": "1618393827655" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#5D9CEC", - "notes": "" - }, - { - "id": "1619605019281", - "component": "httproute", - "tab": "1615551125555", - "name": "GET db", - "x": 70, - "y": 411, - "connections": { - "0": [ - { - "index": "0", - "id": "1619515097737" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "Listening", - "color": "green" - }, - "options": { - "timeout": 5, - "cachepolicy": 0, - "cacheexpire": "5 minutes", - "size": 5, - "url": "/db", - "method": "GET", - "name": "", - "flags": [ - "id:1619605019281", - "get", - 5000 - ] - }, - "color": "#5D9CEC", - "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", - "cloning": false - }, - { - "id": "1619784672383", - "component": "trigger", - "tab": "1615551125555", - "name": "turnOnAlarm", - "x": 82, - "y": 755, - "connections": { - "0": [ - { - "index": "0", - "id": "1618232536546" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "datatype": "object", - "data": "{command: \"turnOnAlarm\"}" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1619784812964", - "component": "trigger", - "tab": "1615551125555", - "name": "turnOffAlarm", - "x": 88, - "y": 819, - "connections": { - "0": [ - { - "index": "0", - "id": "1618232536546" - } - ] - }, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": { - "datatype": "object", - "data": "{command: \"turnOffAlarm\"}" - }, - "color": "#F6BB42", - "notes": "" - }, - { - "id": "1621340721628", - "component": "virtualwireout", - "tab": "1611921777196", - "name": "di_do_controller-in", - "x": 630, - "y": 422, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "di_do_controller-in", - "color": "gray" - }, - "options": { - "wirename": "di_do_controller-in" - }, - "color": "#303E4D", - "notes": "" - } - ], - "version": 615 -} \ No newline at end of file diff --git a/flow/di_do_controller.js b/flow/dido_controller.js similarity index 74% rename from flow/di_do_controller.js rename to flow/dido_controller.js index a218aec..8b5a7b7 100644 --- a/flow/di_do_controller.js +++ b/flow/dido_controller.js @@ -1,9 +1,9 @@ -exports.id = 'di_do_controller'; -exports.title = 'DI_DO_Controller'; -exports.version = '1.0.0'; +exports.id = 'dido_controller'; +exports.title = 'DIDO_Controller'; +exports.version = '2.0.0'; exports.group = 'Worksys'; exports.color = '#2134B0'; -exports.input = 1; +exports.input = 3; exports.output = ["red", "white", "yellow"]; exports.click = false; exports.author = 'Daniel Segeš'; @@ -60,7 +60,7 @@ state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda //globals //FIRMWARE version -FLOW.OMS_edge_fw_version = "2022-05-12";//rok-mesiac-den +FLOW.OMS_edge_fw_version = "2023-10-18";//rok-mesiac-den FLOW.OMS_edgeName = ""; FLOW.OMS_maintenance_mode = false; @@ -142,7 +142,7 @@ exports.install = function(instance) { let twilight_sensor_interval = 5;//minutes let twilight_sensor = []; const twilight_sensor_array = []; - let twighlightError = false; + let twilightError = false; let edgeName = ""; @@ -178,7 +178,7 @@ exports.install = function(instance) { 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["em"] = "OK";//elektromer rvo deviceStatuses["temperature"] = "OK";//templomer deviceStatuses["battery"] = "OK";//Batéria deviceStatuses["power_supply"] = "OK";//Zdroj @@ -187,6 +187,7 @@ exports.install = function(instance) { deviceStatuses["state_of_breaker"] = {};//"Off";//Istič deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač + deviceStatuses["twilight_sensor"] = "OK"; //lux sensor /* dbRelays.on('change', function(doc, old) { @@ -289,8 +290,6 @@ exports.install = function(instance) { edgeName = relaysData[0].tbname; FLOW.OMS_edgeName = edgeName; - logger.debug("RVO tbname:", edgeName); - dataToTb = { [edgeName]: [ { @@ -304,13 +303,27 @@ exports.install = function(instance) { let time = 3*1000; setTimeout(function(){ - instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "buildTasks"}); + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"}); sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", instanceSendTo.tb, instance ); monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version); }, time); } + + + // we ensure, all tasks will be rebuild every day at 11. To set correct switch off and on times + let sendRebuildTasksAt11 = null; + const checkIf11Oclock = () => + { + const d = new Date(); + const h = d.getHours(); + if(h === 11) + { + instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"}); + } + } + sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000); function handleRsPort() @@ -402,9 +415,11 @@ exports.install = function(instance) { function handleWebSocket() { - console.log("handleWebSocket function called"); - ws = new WebSocket('ws:/10.0.0.38:1234/ws') + //to keep websocket opened, we send request every 150 seconds + let startRequests = null; + console.log("handleWebSocket function called"); + ws = new WebSocket('ws:/0.0.0.0:1234/ws'); ws.onopen = function open() { @@ -416,7 +431,13 @@ exports.install = function(instance) { initialSetting(); ws.send(JSON.stringify({"cmd":"all"})); - // startRequests(); + // we request dev info about neuron device from evok to keep websocket connection alive + // for some reason this request returns no data, but connection keeps alive + // https://evok.api-docs.io/1.0/mpqzDwPwirsoq7i5A/websocket + startRequests = setInterval(() => { + // console.log(" *** data from evok requested"); + ws.send(JSON.stringify({"cmd":"filter", "dev": ["neuron"]})); + }, 150000) }; // SAMPLE DATA FROM WEBSOCKET @@ -442,11 +463,9 @@ exports.install = function(instance) { // 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)) @@ -485,32 +504,36 @@ exports.install = function(instance) { ws.on('error', (err) => { instance.send(instanceSendTo.debug, err.message); + clearInterval(startRequests); + startRequests = null; }) ws.onclose = function(){ // connection closed, discard old websocket and create a new one in 5s // stopRequests(); + clearInterval(startRequests); ws = null; - console.log("ws is null now, reconnecting in 5 seconds"); - setTimeout(handleWebSocket, 5000); + console.log("ws is null now, reconnecting..."); + setTimeout(handleWebSocket, 1000); } } - //! do we need requests every minute ??? + // ! 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":"all"})); + // ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"})); // // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]})); - // }, 60000) + // }, 150000) // } instance.on("close", () => { if(rsPort) rsPort.close(); if(ws) ws.close(); + clearInterval(sendRebuildTasksAt11); }) loadAllDb(); @@ -555,7 +578,7 @@ exports.install = function(instance) { } else if(ws) { - let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_08", "value": 1}; + let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1}; ws.send(JSON.stringify(cmd)); logger.debug("sirena zapnuta"); } @@ -579,7 +602,7 @@ exports.install = function(instance) { } else if(ws) { - let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_08", "value": 0}; + let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0}; ws.send(JSON.stringify(cmd)); logger.debug("sirena vypnuta"); } @@ -709,7 +732,7 @@ exports.install = function(instance) { //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) + //switchLogic(pin, 1) } } @@ -724,7 +747,7 @@ exports.install = function(instance) { let values = {}; values["statecode"] = calculateStateCode(); - values["power_mode"] = "Automatic"; + values["power_mode"] = "automatic"; let tbname = relaysData[line].tbname; sendTelemetry(values, tbname); @@ -783,71 +806,92 @@ exports.install = function(instance) { else if(ws) { //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method - monitor.info("turnOffLine pin (relay)", pin); + //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) + //switchLogic(pin, 0) } } - // we expect array as flowdata.data - instance.on("data", (flowdata) => { + //data from modbus_reader or temperature sensor or twilight sensor or other modbus device + instance.on("0", flowdata => { - console.log(flowdata.data); + if(!flowdata.data instanceof Object) return; - if(flowdata.data instanceof Object) + // console.log('***********************', flowdata.data) + instance.send(instanceSendTo.debug, flowdata.data); + + // we handle nok status from modbus_reader component and thermometer + if(flowdata.data?.status) { - - if(flowdata.data.hasOwnProperty("sender")) + const status = flowdata.data.status; + if(status == "NOK-twilight_sensor") { - //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(edgeName)) - { - //rvo - deviceStatuses["rvo"] = {status: flowdata.data.tbdata[edgeName][0]["values"]["status"], tbdata: flowdata.data.tbdata}; - } - else{ - //posli do tb - to je vyriesene na urovni modbus_citysys - //instance.send(instanceSendTo.tb, flowdata.data.tbdata); - } - } - - instance.send(instanceSendTo.debug, flowdata.data ); - return; + deviceStatuses["twilight_sensor"] = "NOK"; + } + else if(status == "NOK-em340" || status == "NOK-em111") + { + deviceStatuses["em"] = "NOK"; + } + else if(status == "NOK-thermometer") + { + deviceStatuses["temperature"] = "NOK"; } - - 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; } + const values = flowdata.data.values; + if(values.hasOwnProperty("twilight_sensor")) + { + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"]}); + deviceStatuses["twilight_sensor"] = "OK" + } + else if(values.hasOwnProperty("temperature")) + { + deviceStatuses["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"; + } + + const updateStatus = checkFinalRVOStatus(); + if(updateStatus) values.status = "OK"; + + sendTelemetry(values, FLOW.OMS_rvo_tbname); + + }) + + + // we expect array as flowdata.data + instance.on("1", flowdata => { + + console.log(flowdata.data); + + if(!flowdata.data instanceof Object) 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(); + + //! ake data prichadzaju z cmd_manager.js ??? //TODO transform to websocket - if (Array.isArray(flowdata.data)){ + if (Array.isArray(obj)){ - rsPort.write(Buffer.from(flowdata.data), function(err) { - switchLogic(flowdata.data); + rsPort.write(Buffer.from(obj), function(err) { + switchLogic(obj); - instance.send(instanceSendTo.debug, {"WRITE":flowdata.data} ); + instance.send(instanceSendTo.debug, {"WRITE":obj} ); }); } }) @@ -859,12 +903,17 @@ exports.install = function(instance) { 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); + 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 + //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY if(!FLOW.OMS_maintenance_mode) { if(deviceStatuses["rotary_switch_state"] == "Manual") @@ -895,48 +944,95 @@ exports.install = function(instance) { { bits.push(0); } - else bits.push(1); + else + { + bits.push(1); + } //EM - if(deviceStatuses["rvo"].status == "NOK") bits.push(1); - else bits.push(0); + if(deviceStatuses["em"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } //Teplomer - if(deviceStatuses["temperature"] == "NOK") bits.push(1); - else bits.push(0); + if(deviceStatuses["temperature"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } //Batéria - if(deviceStatuses["battery"] == "NOK") bits.push(1); - else bits.push(0); + if(deviceStatuses["battery"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } //Zdroj - if(deviceStatuses["power_supply"] == "NOK") bits.push(1); - else bits.push(0); + 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); + 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); + if(deviceStatuses["no_voltage"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } - //console.log("calculateStateCode - deviceStatuses", deviceStatuses); - //console.log("calculateStateCode", bits); + if(deviceStatuses["twilight_sensor"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + // doplnime do 16 bitov (2 byty) + for(let i = bits.length; i < 16; i++) + { + 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); + //console.log("calculateStateCode -------------------", byte); return byte; } @@ -951,10 +1047,18 @@ exports.install = function(instance) { let status = "OK"; - if(deviceStatuses["rvo"].status == "NOK") + if(deviceStatuses["em"] == "NOK") { - let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: rvo status is NOK"); - if(writeToFile) errLogger.error("checkFinalRVOStatus: rvo status is NOK", deviceStatuses["rvo"].tbdata); + let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: EM status is NOK"); + if(writeToFile) errLogger.error("checkFinalRVOStatus: EM status is 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"; } @@ -971,10 +1075,15 @@ exports.install = function(instance) { if(status == "OK") { - for (const pinIndex of [1, 4, 6]) { + 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 && FLOW.OMS_maintenance_mode) continue; + 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); @@ -986,7 +1095,7 @@ exports.install = function(instance) { } } - // battery status. If value is 1 - battery is not ok + // battery status. If value is 1 - battery is NOK if (previousValues[5] === 1) { let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery"); @@ -995,18 +1104,6 @@ exports.install = function(instance) { status = "NOK"; } - //ak mame telemetriu z elektromeru, posleme - if(deviceStatuses["rvo"].tbdata != undefined) - { - //deviceStatuses["rvo"] = {status: flowdata.data.tbdata[edgeName][0]["values"]["status"], tbdata: flowdata.data.tbdata}; - - deviceStatuses["rvo"].tbdata[edgeName][0]["values"]["status"] = status; - - - instance.send(instanceSendTo.tb, deviceStatuses["rvo"].tbdata); - delete deviceStatuses["rvo"].tbdata; - } - //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding); if(!FLOW.OMS_masterNodeIsResponding) @@ -1033,17 +1130,7 @@ exports.install = function(instance) { if(status == "NOK") { - - const dataToTb = { - [edgeName]: [ - { - "ts": Date.now(), - "values": {status: "NOK"} - } - ] - } - - instance.send(instanceSendTo.tb, dataToTb); + sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname); return false; } @@ -1052,21 +1139,22 @@ exports.install = function(instance) { } - - // we pass array to function in case of rsPort [[55,3,0,1]] - // we pass two values in case of websocket [3,1] + // we pass array to function in case of rsPort ==> switchLogic([55,3,0,1]) ==> [[55,3,0,1]] + // 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, twighlight; + let dataToTb, pinIndex, newPinValue, twilight; + //data from rsPort if(args.length == 1) { pinIndex = args[0][1] + 1; if (pinIndex === 17) pinIndex--; newPinValue = args[0][3]; - twighlight = args[0][2]; + twilight = args[0][2]; } + //data from websocket else { pinIndex = args[0]; @@ -1090,7 +1178,9 @@ exports.install = function(instance) { if(newPinValue === 0) value = "Off"; //Hlavný istič - if(type === "state_of_main_switch") + //! 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]) { @@ -1116,16 +1206,26 @@ exports.install = function(instance) { { pin2 = newPinValue; pin3 = previousValues[3] || previousValues["input1_03"]; - if (pin3 == undefined) pin3 = 0; + + 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) pin2 = 0; + + if(pin2 == undefined) + { + previousValues[pinIndex] = newPinValue; + return; + } } - value = "Off"; + //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"; @@ -1136,7 +1236,7 @@ exports.install = function(instance) { //ak je spracovany, a automatic - tak ho zapnem //ak nie je spracovany, iba profil zapisem - instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "rotary_switch_state", value: value}); + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value}); //console.log("rotary_switch_state pin", pin2, pin3, value); } @@ -1179,7 +1279,9 @@ exports.install = function(instance) { } } //Dverový kontakt - pin 6 - else if(type == "door_condition") + //! 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' + else if(type == "door_condition" || type === "state_of_main_switch") { newPinValue === 0 ? value = "open" : value = "closed"; @@ -1202,8 +1304,9 @@ exports.install = function(instance) { //console.log(door_has_been_open_without_permision_alarm_is_on); - //zapneme sirenu - turnOnAlarm(); + // 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 (value === "closed") @@ -1217,73 +1320,84 @@ exports.install = function(instance) { deviceStatuses["door_condition"] = value; } + //lux sensor 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", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, instanceSendTo.tb, instance ); - newPinValue = 0; - } - else if (set.size !== 1 && twighlightError) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", instanceSendTo.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(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "lux_sensor", value: average}); - - twilight_sensor = []; - - //console.log("lux_sensor send", average); - } - //else console.log("lux_sensor", value, diff); - + //! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000. + //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') + { + value = parseFloat(newPinValue + (256*twilight)); + + 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 && !twilightError) + { + twilightError = true; + values["status"] = "NOK"; + let value = twilight_sensor_array.shift(); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, instanceSendTo.tb, instance ); + newPinValue = 0; + } + else if (set.size !== 1 && twilightError) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", instanceSendTo.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) + { + const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length; + instance.send(instanceSendTo.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); + } } else if(type == "state_of_contactor") { //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", instanceSendTo.tb, instance ); - sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", instanceSendTo.tb, instance ); - deviceStatuses["state_of_contactor"][line] = value; - + if(!(deviceStatuses["state_of_contactor"][line] == value)) + { + sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", instanceSendTo.tb, instance ); + } + else + { + deviceStatuses["state_of_contactor"][line] = value; + } + //true, false if(value === "On") value = true; else if(value === "Off") value = false; @@ -1319,7 +1433,7 @@ exports.install = function(instance) { //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor setTimeout(function(){ - instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); }, time); reportLineStatus(line); @@ -1344,7 +1458,24 @@ exports.install = function(instance) { if(valueChanged) { - instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "state_of_breaker", value: value, line: line}); + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line}); + + //mame 3 istice. ked je viac ako 3 linie, dalsie sa zapajaju paralelne. to znamena na istici 1 je linia 1 a 4, na istici 2 je linia 2 a 5, na istici 3 je linia 3 a 6 (key je string ("4")) + //vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia + const lineOnSameBraker = line + 3 + ""; + + if(relaysData.hasOwnProperty(lineOnSameBraker)) { + instance.send(instanceSendTo.cmd_manager, {sender: "di_do_controller", cmd: "state_of_breaker", value: value, line: line + 3}); + + deviceStatuses["state_of_breaker"][line + 3] = value; + reportLineStatus(line + 3); + + values[type] = value; + tbname = relaysData[lineOnSameBraker].tbname; + sendTelemetry(values, tbname); + + delete values[type]; + } } if(value == "Off") values["status"] = "NOK"; @@ -1352,25 +1483,27 @@ exports.install = function(instance) { deviceStatuses["state_of_breaker"][line] = value; reportLineStatus(line); - } values[type] = value; - - let result = checkFinalRVOStatus(); - if(!result && line == 0) - { - values["status"] = "NOK"; - } - - //-- //if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode(); if(pinsData.hasOwnProperty(pinIndex)) { let valueChanged = false; - if(newPinValue != previousValues[pinIndex]) valueChanged = true; + 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; @@ -1381,15 +1514,14 @@ exports.install = function(instance) { if(FLOW.OMS_rvo_tbname == "") { - console.log("FLOW.OMS_rvo_tbname is EMPTY"); + 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); + //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname); } - if(valueChanged) { @@ -1412,11 +1544,8 @@ exports.install = function(instance) { logger.debug("no pinIndex", pinsData[pinIndex], pinsData); } - //pin was changed - previousValues[pinIndex] = newPinValue; + } - - } function sendTelemetry(values, tbname) { @@ -1431,8 +1560,6 @@ exports.install = function(instance) { instance.send(instanceSendTo.tb, dataToTb); } - - } @@ -1695,22 +1822,18 @@ exports.install = function(instance) { //! 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|........... +// *|input1_01|state_of_main_switch|0|........... +// *|input1_02|rotary_switch_state|0|........... +// *|input1_03|rotary_switch_state|0|........... +// *|intut1_04|power_supply|0|........... +// *|input1_05|door_condition|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|........... +// *|287D8776E0013CE9|temperature|0|........... //! pins_data --> from UNIPI @@ -1762,3 +1885,28 @@ exports.install = function(instance) { // } // } + + + + +// { +// "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV": [ +// { +// "ts": 1700409326353, +// "values": { +// "_event": { +// "type": "notice", +// "status": "new", +// "source": { +// "func": "rsPort.open()", +// "component": "1700343402190", +// "component_name": "DIDO_Controller", +// "edge": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV" +// }, +// "message": "al_shariff_10.0.0.38: FLOW has been started ", +// "message_data": "" +// } +// } +// } +// ] +// } \ No newline at end of file diff --git a/flow/gettemperature.js b/flow/gettemperature.js index 171cc96..720592a 100644 --- a/flow/gettemperature.js +++ b/flow/gettemperature.js @@ -1,18 +1,18 @@ -exports.id = 'gettemperature'; +exports.id = 'thermometer'; exports.title = 'Thermometer'; exports.group = 'Worksys'; exports.color = '#5CB36D'; -exports.version = '1.0.2'; +exports.version = '1.0.3'; exports.output = ["red", "white", "blue"]; exports.author = 'Rastislav Kovac'; exports.icon = 'thermometer-three-quarters'; -exports.readme = `# Getting temperature values from RVO`; +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, - di_do_controller: 2 + dido_controller: 2 } //read temperature - frequency @@ -43,7 +43,7 @@ const monitor = log4js.getLogger("monitorLogs"); //monitor.info('info'); //errLogger.error("some error"); -const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); +const { promisifyBuilder } = require('./helper/db_helper'); const dbSettings = TABLE("settings"); let temperatureAddress = ""; @@ -60,7 +60,7 @@ loadSettings(); exports.install = function(instance) { const { exec } = require('child_process'); - const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js'); + const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter'); let startRead; let dataToTb; @@ -76,9 +76,9 @@ exports.install = function(instance) { }) - const start = function(){ + const start = function() { - try{ + try { if(FLOW.OMS_controller_type === "unipi") { @@ -130,8 +130,8 @@ exports.install = function(instance) { monitor.info("Thermometer is not responding", error, FLOW.OMS_brokerready); - instance.send(instanceSendTo.tb, dataToTb); - instance.send(instanceSendTo.di_do_controller, {sender: "gettemperature", status: status}); + // 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); } @@ -162,10 +162,9 @@ exports.install = function(instance) { logger.debug("gettemperature", data); - if (!isNaN(data)){ + if(!isNaN(data)) { - - //if ( counter > 290 ) + if(counter > 290) { instance.send(instanceSendTo.debug, "[Get temperature component] - temperature data are comming again from RVO after more than 1 day break"); @@ -174,21 +173,22 @@ exports.install = function(instance) { } logger.debug("gettemperature", data); + const values = { + "temperature": Number(data.toFixed(2)), + "status": "OK" + } dataToTb = { [edgeName]: [ { "ts": Date.now(), - "values": { - "temperature": Number(data.toFixed(2)), - "status": "OK" - } + "values":values } ] } instance.send(instanceSendTo.tb, dataToTb); - instance.send(instanceSendTo.di_do_controller, {sender: "gettemperature", status: "OK"}); + instance.send(instanceSendTo.dido_controller, values); counter = 0; @@ -204,9 +204,8 @@ exports.install = function(instance) { 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.di_do_controller, {sender: "gettemperature", status: "NOK"}); + instance.send(instanceSendTo.dido_controller, {status: "NOK-thermometer"}); } - } } @@ -216,5 +215,4 @@ exports.install = function(instance) { }, 3000); startRead = setInterval(start, timeoutMin * 1000 * 60); - }; \ No newline at end of file diff --git a/flow/helper/ErrorToServiceHandler.js b/flow/helper/ErrorToServiceHandler.js index 5adc29a..dc60446 100644 --- a/flow/helper/ErrorToServiceHandler.js +++ b/flow/helper/ErrorToServiceHandler.js @@ -1,124 +1,124 @@ -const { MD5 } = require('./md5.js'); -const { networkInterfaces } = require('os'); - -class ErrorToServiceHandler -{ - constructor() { - this.previousValues = {}; - - this.projects_id = undefined; - this.message_type = "error_message"; - - const nets = networkInterfaces(); - this.ipAddresses = Object.create(null); // Or just '{}', an empty object - - for (const name of Object.keys(nets)) { - for (const net of nets[name]) { - // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses - if (net.family === 'IPv4' && !net.internal) { - if (!this.ipAddresses[name]) { - this.ipAddresses[name] = []; - } - this.ipAddresses[name].push(net.address); - } - } - } - - //console.log(this.ipAddresses); - - } - - setProjectsId(projects_id) - { - this.projects_id = projects_id; - } - - processMessage(message, seconds, message_type) - { - if(Array.isArray(message)) message = message.join(', '); - //keep in memory - default value is 1h - if (seconds === undefined) seconds = 60*60; - if(message_type) this.message_type = message_type; - - let key = MD5(message); - let timestamp = new Date().getTime(); - - if(!this.previousValues.hasOwnProperty(key)) - { - this.previousValues[key] = {ts: timestamp, duration: seconds}; - } - - let diff = (timestamp - this.previousValues[key].ts); - if(diff < this.previousValues[key].duration*1000) return false; - - this.previousValues[key].ts = timestamp; - - return true; - } - - sendMessageToService(message, seconds, message_type) - { - - let f = this.processMessage(message, seconds, message_type); - if(!f) return; - - /* - //------------- - if(message_type == undefined) message_type = "error_message"; - if(Array.isArray(message)) message = message.join(', '); - - let key = MD5(message); - let timestamp = new Date().getTime(); - - //keep in memory - if (seconds === undefined) seconds = 60*60; - - if(!this.previousValues.hasOwnProperty(key)) - { - this.previousValues[key] = {ts: timestamp, duration: seconds}; - } - - let diff = (timestamp - this.previousValues[key].ts); - if(diff < this.previousValues[key].duration*1000) return; - - this.previousValues[key].ts = timestamp; - */ - - //------------------------- - - //send to service - - let dataToInfoSender = {id: this.projects_id}; - - //js_error || error_message - dataToInfoSender[this.message_type] = message; - dataToInfoSender.ipAddresses = this.ipAddresses; - - console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender); - - //TODO UGLY!!! - if(this.projects_id === undefined) this.projects_id = FLOW.OMS_projects_id; - - /* - if(this.projects_id === undefined) - { - console.log("this.projects_id is undefined"); - return; - } - */ - - RESTBuilder.make(function(builder) { - builder.method('POST'); - builder.post(dataToInfoSender); - builder.url('http://192.168.252.2:8004/sentmessage'); - - builder.callback(function(err, response, output) { - console.log("process.on error send", err, response, output, dataToInfoSender); - }); - }); - - - } -} - +const { MD5 } = require('./md5.js'); +const { networkInterfaces } = require('os'); + +class ErrorToServiceHandler +{ + constructor() { + this.previousValues = {}; + + this.projects_id = undefined; + + const nets = networkInterfaces(); + this.ipAddresses = Object.create(null); // Or just '{}', an empty object + + for (const name of Object.keys(nets)) { + for (const net of nets[name]) { + // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses + if (net.family === 'IPv4' && !net.internal) { + if (!this.ipAddresses[name]) { + this.ipAddresses[name] = []; + } + this.ipAddresses[name].push(net.address); + } + } + } + + //console.log(this.ipAddresses); + + } + + setProjectsId(projects_id) + { + this.projects_id = projects_id; + } + + processMessage(message, seconds, message_type) + { + if(message_type == undefined) message_type = "error_message"; + if(Array.isArray(message)) message = message.join(', '); + + let key = MD5(message); + let timestamp = new Date().getTime(); + + //keep in memory - default value is 1h + if (seconds === undefined) seconds = 60*60; + + if(!this.previousValues.hasOwnProperty(key)) + { + this.previousValues[key] = {ts: timestamp, duration: seconds}; + } + + let diff = (timestamp - this.previousValues[key].ts); + if(diff < this.previousValues[key].duration*1000) return false; + + this.previousValues[key].ts = timestamp; + + return true; + } + + sendMessageToService(message, seconds, message_type) + { + + let f = this.processMessage(message, seconds, message_type); + if(!f) return; + + /* + //------------- + if(message_type == undefined) message_type = "error_message"; + if(Array.isArray(message)) message = message.join(', '); + + let key = MD5(message); + let timestamp = new Date().getTime(); + + //keep in memory + if (seconds === undefined) seconds = 60*60; + + if(!this.previousValues.hasOwnProperty(key)) + { + this.previousValues[key] = {ts: timestamp, duration: seconds}; + } + + let diff = (timestamp - this.previousValues[key].ts); + if(diff < this.previousValues[key].duration*1000) return; + + this.previousValues[key].ts = timestamp; + */ + + //------------------------- + + //send to service + + let dataToInfoSender = {id: this.projects_id}; + + //js_error || error_message + dataToInfoSender[message_type] = message; + dataToInfoSender.ipAddresses = this.ipAddresses; + + console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender); + + //TODO UGLY!!! + if(this.projects_id === undefined) this.projects_id = FLOW.OMS_projects_id; + + /* + if(this.projects_id === undefined) + { + console.log("this.projects_id is undefined"); + return; + } + */ + + RESTBuilder.make(function(builder) { + builder.method('POST'); + builder.post(dataToInfoSender); + builder.url('http://192.168.252.2:8004/sentmessage'); + + builder.callback(function(err, response, output) { + console.log("process.on error send", err, response, output, dataToInfoSender); + }); + }); + + + } +} + module.exports = ErrorToServiceHandler; \ No newline at end of file diff --git a/flow/helper/notification_reporter.js b/flow/helper/notification_reporter.js index 566b93f..84b2345 100644 --- a/flow/helper/notification_reporter.js +++ b/flow/helper/notification_reporter.js @@ -1,135 +1,137 @@ - -const { promisifyBuilder, makeMapFromDbResult } = require('./db_helper.js'); -const dbNotifications = TABLE("notifications"); - -//key is device, value = str -let sentValues= {}; -let notificationsData = {}; - -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 -}; - -function getKey(map, val) { - return Object.keys(map).findItem(key => map[key] === 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 sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) { - - let storeToSendValues = true; - if(saveKey == undefined) storeToSendValues = false; - - let lang = FLOW.OMS_language; - if(lang != "en" || lang != "sk") lang = "en"; - - let tpl = key; - let weight = ""; - - if(notificationsData[key]) - { - weight = notificationsData[key].weight; - weight = weight.toLowerCase(); - - tpl = notificationsData[key][lang]; - tpl = template(tpl, params); - } - else - { - console.error("sendNotification: Notifications: undefined key", key, func, notificationsData); - return false; - } - - //detect invalid err weight - if(getKey(ERRWEIGHT, weight) == undefined) - { - console.error("sendNotification: Notifications: undefined weight", weight, key, func); - return false; - } - - if(sentValues.hasOwnProperty(saveKey)) - { - if(sentValues[saveKey] == tpl) - { - return false; - } - } - - if(sentValues[saveKey] == undefined) - { - if(storeToSendValues) - { - //do not send - flow is was started - sentValues[saveKey] = tpl; - return false; - } - } - - if(saveKey == "rvo_door") - { - //console.log("******", saveKey, sentValues[saveKey], tpl); - } - - if(storeToSendValues) sentValues[saveKey] = tpl; - - let str = FLOW.OMS_rvo_name; - if(str != "") str = str + ": "; - str = str + tpl; - - 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 - - return true; - -} - -module.exports = { - sendNotification, - initNotifications, - ERRWEIGHT + +const { promisifyBuilder, makeMapFromDbResult } = require('./db_helper.js'); +const dbNotifications = TABLE("notifications"); + +//key is device, value = str +let sentValues= {}; +let notificationsData = {}; + +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 +}; + +function getKey(map, val) { + return Object.keys(map).findItem(key => map[key] === 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 sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) { + + // return; + + let storeToSendValues = true; + if(saveKey == undefined) storeToSendValues = false; + + let lang = FLOW.OMS_language; + if(lang != "en" || lang != "sk") lang = "en"; + + let tpl = key; + let weight = ""; + + if(notificationsData[key]) + { + weight = notificationsData[key].weight; + weight = weight.toLowerCase(); + + tpl = notificationsData[key][lang]; + tpl = template(tpl, params); + } + else + { + console.error("sendNotification: Notifications: undefined key", key, func, notificationsData); + return false; + } + + //detect invalid err weight + if(getKey(ERRWEIGHT, weight) == undefined) + { + console.error("sendNotification: Notifications: undefined weight", weight, key, func); + return false; + } + + if(sentValues.hasOwnProperty(saveKey)) + { + if(sentValues[saveKey] == tpl) + { + return false; + } + } + + if(sentValues[saveKey] == undefined) + { + if(storeToSendValues) + { + //do not send - flow is was started + sentValues[saveKey] = tpl; + return false; + } + } + + if(saveKey == "rvo_door") + { + //console.log("******", saveKey, sentValues[saveKey], tpl); + } + + if(storeToSendValues) sentValues[saveKey] = tpl; + + let str = FLOW.OMS_rvo_name; + if(str != "") str = str + ": "; + str = str + tpl; + + 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 + + return true; + +} + +module.exports = { + sendNotification, + initNotifications, + ERRWEIGHT } \ No newline at end of file diff --git a/flow/infosender.js b/flow/infosender.js index 5043687..a83499c 100644 --- a/flow/infosender.js +++ b/flow/infosender.js @@ -22,16 +22,12 @@ exports.html = `
exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`; -const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); const fs = require('fs'); var path = require('path'); exports.install = async function(instance) { - let id; let allValues = {}; - let dbSettings; - let sendAllValuesInterval; let now = new Date(); @@ -52,23 +48,11 @@ exports.install = async function(instance) { } } - try { - let p = path.join(__dirname + "/../databases/", 'settings.table'); - if (fs.existsSync(p)) { - - dbSettings = TABLE("settings"); - let responseSettings = await promisifyBuilder(dbSettings.find()); - id = responseSettings[0]["projects_id"]; - - //console.log(exports.title, responseSettings, id); - } - } catch(err) { - console.error(err); - } - function sendValues() { + const id = FLOW.OMS_projects_id; + if(Object.keys(allValues).length > 0) { if(id !== undefined) diff --git a/flow/modbus_citysys.js b/flow/modbus_citysys.js deleted file mode 100644 index d038b69..0000000 --- a/flow/modbus_citysys.js +++ /dev/null @@ -1,1127 +0,0 @@ -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 = `
-
-
-
Edge TB Name
-
-
-
`; - -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 new file mode 100644 index 0000000..d21839d --- /dev/null +++ b/flow/modbus_reader.js @@ -0,0 +1,336 @@ +exports.id = 'modbus_reader'; +exports.title = 'Modbus reader'; +exports.version = '2.0.0'; +exports.group = 'Worksys'; +exports.color = '#2134B0'; +exports.output = ["red", "white"]; +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 ErrorToServiceHandler = require('./helper/ErrorToServiceHandler'); +const errorHandler = new ErrorToServiceHandler(); + +const { sendNotification } = require('./helper/notification_reporter'); + +const instanceSendTo = { + debug: 0, + dido_controller: 1, +}; + +//to handle NOK and OK sendNotifications s +const numberOfNotResponding = {}; +let tbName = null; + + +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; + + // kedze potrebujeme ist stale dookola pre jednotlive zariadenia, potrebujeme ci uz index ako aj adresu zariadenia, a aj pocet registrov na vycitanie + this.deviceAddress = null; // adresa zariadenia (1 ma EM340 a 2 ma twilight_sensor) + this.indexInDeviceConfig = 0; // prvy item v deviceConfig + this.lengthOfActualDeviceStream = null; + this.device = null; + + 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); + } + + 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; + }) + + }; + + 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, 2000); + } + + 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, {}, "", instanceSendTo.tb, instance); + delete numberOfNotResponding[obj.device]; + } + + obj.transformResponse(resp, register, obj.deviceAddress); + + obj.error = 0; + obj.index++; + + if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0); + else obj.setNewStream(); + + }).catch (function () { + + console.log("error pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute); + + obj.error++; + if(obj.error == obj.lengthOfActualDeviceStream) + { + instance.send(instanceSendTo.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, {}, "", instanceSendTo.tb, instance); + numberOfNotResponding[obj.device] = 1; + } + + obj.error = 0; + numberOfNotResponding[obj.device] += 1; + } + + console.error(require('util').inspect(arguments, { + depth: null + })) + + obj.index++; + if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0); + else obj.setNewStream(); + }) + + }; + + transformResponse = (response, register, deviceAddress) => { + + 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(deviceAddress, register, tbName, tbAttribute, response, a.multiplier, value); + + // if(tbName == undefined) return; + + if(this.index + 1 + this.errors < this.lengthOfActualDeviceStream) + { + this.allValues[tbAttribute] = value; + return; + } + + const values = { + ...this.allValues, + [tbAttribute]: value, + }; + + this.checkNullVoltage(values); + + instance.send(instanceSendTo.dido_controller, {values: values}); + + this.allValues = {}; + break; + } + + } + + } + + setNewStream = () => + { + // console.log('------------',this.lengthOfActualDeviceStream, this.index); + // console.log('------------',this.indexInDeviceConfig, deviceConfig.length); + if(this.lengthOfActualDeviceStream == this.index) + { + if(this.indexInDeviceConfig + 1 == deviceConfig.length) + { + this.indexInDeviceConfig = 0; + } + else + { + this.indexInDeviceConfig += 1; + } + + this.getActualStreamAndDevice(); + } + } + + + // sendFinalObjects = (values) => + // { + + // const date = Date.now(); + // // values["status"] = "OK"; + + // const dataToTB = { + // [tbName]: [ + // { + // "ts": date, + // "values": values + // } + // ] + // }; + + // instance.send(instanceSendTo.tb, dataToTB); + + // const dataToDiDo = { + // values: values + // } + + // instance.send(instanceSendTo.dido_controller, dataToDiDo); + // } + + + 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_citys: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase ); + // console.log('no voltage') + } + else + { + FLOW.OMS_no_voltage.delete(phase); + // console.log('voltage detected') + sendNotification("modbus_citys: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase); + } + } + }) + } + + // we use dataToTbHandler. Therefore we need to check, if objects we send to dido_controller are not empty + isObjectEmpty = (objectName) => { + return Object.keys(objectName).length === 0 && objectName.constructor === Object; + } + } + + setTimeout(() => { + const newSocket = new SocketWithClients(); + tbName = FLOW.OMS_rvo_tbname; + }, 25000); +} diff --git a/flow/monitorcpu.js b/flow/monitorcpu.js deleted file mode 100644 index 0e906d1..0000000 --- a/flow/monitorcpu.js +++ /dev/null @@ -1,107 +0,0 @@ -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 deleted file mode 100644 index e34c940..0000000 --- a/flow/mqtt.js +++ /dev/null @@ -1,441 +0,0 @@ -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
-
-
-
Port
-
-
-
-
-
@(Client id)
-
@(Supports variables, example: \`client_{device-id}\`)
-
@(Secure (ssl))
-
-
-
-
-
-
@(Require Authorization)
-
-
-
-
-
@(Username)
-
-
-
@(Password)
-
-
-
-
-
-
@(LWT)
-
-
-
-
-
@(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 deleted file mode 100644 index b9d778d..0000000 --- a/flow/mqtt_listener.js +++ /dev/null @@ -1,171 +0,0 @@ -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
-
-
-
Port
-
-
-
-
-
@(Client id)
-
-
-
@(Username)
-
-
-
`; - - -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/mqttpublish.js b/flow/mqttpublish.js deleted file mode 100644 index 3f6aef0..0000000 --- a/flow/mqttpublish.js +++ /dev/null @@ -1,134 +0,0 @@ -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 deleted file mode 100644 index e866178..0000000 --- a/flow/mqttsubscribe.js +++ /dev/null @@ -1,168 +0,0 @@ -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/nosql.js b/flow/nosql.js deleted file mode 100644 index db6b7c4..0000000 --- a/flow/nosql.js +++ /dev/null @@ -1,191 +0,0 @@ -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/relays.js b/flow/relays.js deleted file mode 100644 index 726abd6..0000000 --- a/flow/relays.js +++ /dev/null @@ -1,357 +0,0 @@ -exports.id = 'relay'; -exports.title = 'DI_DO_Controller'; -exports.version = '1.0.0'; -exports.group = 'Worksys'; -exports.color = '#2134B0'; -exports.input = 1; -exports.output = ["red", "white", "yellow"]; -exports.click = false; -exports.author = 'Daniel Segeš'; -exports.icon = 'bolt'; -exports.options = { edge: "undefined" }; - -exports.html = `
-
-
-
Edge TB Name
-
-
-
`; - -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 -*/ - -exports.install = function(instance) { - - let previousValues = {}; - let rsPortReceivedData = []; - - console.log("DI_DO_Relay_Controller installed"); - - //key is PIN number - const conversionTable = { - "1": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "state_of_main_switch"}, //state_of_main_switch pin1 - "2": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "rotary_switch_state"}, //rotary_switch_state - poloha manual = pin2 - "3": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "rotary_switch_state"}, //rotary_switch_state - poloha auto = pin3 - "6": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "door_condition"}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open - "8": {tbname: "RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on - "9": {tbname: "dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on - "10": {tbname: "vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on - "11": {tbname: "RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on - "12": {tbname: "dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on - "13": {tbname: "vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on - "16": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "state_of_main_switch"}, // twilight_sensor = pin16 - }; - - const dbRelays = TABLE("relays"); - dbRelays.on('change', function(doc, old) { - instance.send(2, "reload_relays"); - }); - - //modify - - const SerialPort = require('serialport'); - //const { exec } = require('child_process'); - const { openPort, runSyncExec, writeData } = require('./serialport_helper.js'); - - const setRSPortData = [0xAA,6,6,6,6,0,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,0,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,0,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0]; - const rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false }); - - 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) { - instance.send(0, exports.title + " runSyncExec - Promise Resolved:" + status); - - //set port - rsPort.write(Buffer.from(setRSPortData), function(err) { - instance.send(0, exports.title + " Digital in_out has been set"); - - //force turn off relays - let keys = Object.keys(conversionTable); - for(let i = 0; i < keys.length; i++) - { - let key = keys[i]; - - if(conversionTable[key].type == "state_of_contactor") - { - let pin = key - 1; - let line = conversionTable[key].line; - - turnOff(line, pin); - } - } - - //dbRelays.modify({ contactor: 0 }); - }) - - }).catch(function (reason) { - instance.send(0, exports.title + " runSyncExec - promise rejected:" + reason); - }); - - }); - - rsPort.open(); - - 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('error', function(err) { - instance.send(0, err.message); - }) - - rsPort.on("close", () => { - rsPort.close(); - }) - - instance.on("close", () => { - rsPort.close(); - }) - - function getPin(line) - { - //conversionTable - let keys = Object.keys(conversionTable); - for(let i = 0; i < keys.length; i++) - { - let key = keys[i]; - - if(conversionTable[key].type == "state_of_contactor" && conversionTable[key].line == line) - { - return key - 1; - } - } - - console.log("no pin detected"); - - return null; - } - - function turnOn(line, pin) - { - if( pin === undefined) pin = getPin(line); - if( pin === undefined) return; - - let arr = [0x55]; - arr.push( pin ); - arr.push( 0 ); - arr.push( 1 ); - - if(!rsPort.isOpen) - { - console.log("port is not opened"); - return; - } - - rsPort.write(Buffer.from(arr), function(err) { - switchLogic(arr); - }); - } - - function turnOff(line, pin) - { - if( pin === undefined) pin = getPin(line); - if( pin === undefined) return; - - let arr = [0x55]; - arr.push( pin ); - arr.push( 0 ); - arr.push( 0 ); - - if(!rsPort.isOpen) - { - console.log("port is not opened"); - return; - } - - rsPort.write(Buffer.from(arr), function(err) { - switchLogic(arr); - }); - } - - // we expect array as flowdata.data - instance.on("data", (flowdata) => { - - //console.log(flowdata.data); - - if(flowdata.data instanceof Object) - { - let obj = flowdata.data; - - let line = obj.line; - - if(obj.command == "turnOn") turnOn(line); - else if(obj.command == "turnOff") turnOff(line); - - return; - } - - if (Array.isArray(flowdata.data)){ - rsPort.write(Buffer.from(flowdata.data), function(err) { - switchLogic(flowdata.data); - - instance.send(0,{"WRITE":flowdata.data}); - }); - } - }) - - const switchLogic = (rsPortReceivedData) => { - - let dataToTb; - let values = {}; - - let pinIndex = rsPortReceivedData[1] + 1; - if (pinIndex === 17) pinIndex--; - - let newPinValue = rsPortReceivedData[3]; - - let obj = conversionTable[pinIndex]; - - if(obj == undefined) - { - //console.log("undefined pinIndex", pinIndex, rsPortReceivedData); - return; - } - - let type = obj.type; - let line = obj.line; - let tbname = obj.tbname; - - //default value - let value = "On"; - if(newPinValue === 0) value = "Off"; - - if(type == "rotary_switch_state") - { - // combination of these two pins required to get result - let pin2, pin3; - if(pinIndex == 2) - { - pin2 = newPinValue; - pin3 = previousValues[pinIndex]; - if (pin3 == undefined) pin3 = 0; - } - else if(pinIndex == 3) - { - pin3 = newPinValue; - pin2 = previousValues[1]; - if (pin2 == undefined) pin2 = 0; - } - - if (pin2 == 1 && pin3 == 0) value = "Manual"; - if (pin2 == 0 && pin3 == 0) value = "Off"; - if (pin2 == 0 && pin3 == 1) value = "Automatic"; - } - else if(type == "door_condition") - { - newPinValue === 0 ? value = "Open" : value = "Closed"; - } - else if(type == "twilight_sensor") - { - value = parseFloat(newPinValue + (256*rsPortReceivedData[2])); - } - else if(type == "state_of_contactor") - { - //modify table relays - dbRelays.modify({ contactor: newPinValue }).where("line", line); - } - - values[obj.type] = value; - - if(conversionTable.hasOwnProperty(pinIndex)) - { - let insertIntoTb = false; - if(newPinValue != previousValues[pinIndex]) insertIntoTb = true; - if(obj.hasOwnProperty("state_of_contactor")) insertIntoTb = true; - - if(insertIntoTb) - { - dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - instance.send(1, dataToTb); - } - } - - //pin was changed - previousValues[pinIndex] = newPinValue; - } -} - - diff --git a/flow/test.js b/flow/test.js deleted file mode 100644 index f0ca813..0000000 --- a/flow/test.js +++ /dev/null @@ -1,120 +0,0 @@ -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 new file mode 100644 index 0000000..1a5714f --- /dev/null +++ b/flow/thermometer.js @@ -0,0 +1,220 @@ +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 diff --git a/flow/wsmqttpublish.js b/flow/wsmqttpublish.js index 8d793ac..794fedc 100644 --- a/flow/wsmqttpublish.js +++ b/flow/wsmqttpublish.js @@ -119,6 +119,7 @@ process.on('uncaughtException', function (err) { const nosql = NOSQL('tbdata'); const nosqlBackup = NOSQL('/backup/tbdata'); + exports.install = function(instance) { var broker; @@ -186,7 +187,7 @@ exports.install = function(instance) { 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]); opts = { @@ -203,8 +204,7 @@ exports.install = function(instance) { } connectToTbServer(); - - } + } function connectToTbServer() { @@ -215,16 +215,18 @@ exports.install = function(instance) { broker.on('connect', function() { instance.status("Connected", "green"); - brokerready = true; + monitor.info("MQTT broker connected"); + + brokerready = true; FLOW.OMS_brokerready = brokerready; - wsmqtt_status = 'connected'; + wsmqtt_status = 'connected'; }); broker.on('reconnect', function() { instance.status("Reconnecting", "yellow"); brokerready = false; - - FLOW.OMS_brokerready = brokerready; + + FLOW.OMS_brokerready = brokerready; }); broker.on('message', function(topic, message) { @@ -243,7 +245,6 @@ exports.install = function(instance) { } instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message }); - }); broker.on('close', function(err) { @@ -258,11 +259,14 @@ exports.install = function(instance) { instance.status("Disconnected", "red"); instance.send(instanceSendTo.debug, {"message":"Broker CLOSE signal received !", "error":err, "opt":opts }); } + + broker.reconnect(); }); broker.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; @@ -270,89 +274,66 @@ exports.install = function(instance) { }); - //broker = new Broker(opts); - //MQTT_BROKERS.push(broker); - - //instance.status('Ready'); } - //set opts accortding to options - /* - instance.reconfigure = function() { + instance.on('data', function(data) { - - var o = instance.options; - opts = { - host: o.host, - port: o.port, - keepalive: 10, - clientId: o.clientid, - username: o.username, - rejectUnauthorized: false, - resubscribe: false - }; - - //connectToTbServer(); - }; - */ - - instance.on('data', function(data) { - - if (brokerready) + if (brokerready) + { + //do we have some data in backup file? + //if any, process data from database + if(saveTelemetryOnError) { - //do we have some data in backup file? - //if any, process data from database - if(saveTelemetryOnError) + //read telemetry data and send back to server + if(!processingData) processDataFromDatabase(); + } + + } + + if (brokerready) + { + let stringifiedJson = JSON.stringify(data.data); + broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1}); + + //backup telemetry + if(createTelemetryBackup) + { + data.data.id = UID(); + nosqlBackup.insert(data.data); + + insertBackupNoSqlCounter++; + if(insertBackupNoSqlCounter > 150) { - //read telemetry data and send back to server - if(!processingData) processDataFromDatabase(); - } - + let options = {compress: true}; + let path = __dirname + "/../databases/backup/tbdata.nosql"; + var stream = new rollers.RollingFileStream(path, noSqlFileSizeLimit, 150, options); + stream.write(""); + stream.end(); + + insertBackupNoSqlCounter = 0; + } + } + + } + 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 }); + + if(saveTelemetryOnError) + { + //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql + makeBackupFromDbFile(); + + //write to tb + data.data.id = UID(); + nosql.insert(data.data); } - if (brokerready) - { - let stringifiedJson = JSON.stringify(data.data); - broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1}); + } + }); - //backup telemetry - if(createTelemetryBackup) - { - data.data.id = UID(); - nosqlBackup.insert(data.data); - - insertBackupNoSqlCounter++; - if(insertBackupNoSqlCounter > 150) - { - let options = {compress: true}; - let path = __dirname + "/../databases/backup/tbdata.nosql"; - var stream = new rollers.RollingFileStream(path, noSqlFileSizeLimit, 150, options); - stream.write(""); - stream.end(); - - insertBackupNoSqlCounter = 0; - } - } - - } - 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 }); - - if(saveTelemetryOnError) - { - //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql - makeBackupFromDbFile(); - - //write to tb - data.data.id = UID(); - nosql.insert(data.data); - } - - } - }); instance.close = function(done) { if (brokerready){ @@ -449,7 +430,6 @@ exports.install = function(instance) { fs.truncateSync(source, 0); } - } const processDataFromDatabase = async () => { diff --git a/package.json b/package.json index 8a8344f..e524d7c 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "version": "1.0.0", "main": "debug.js", "dependencies": { - "easy-crc": "0.0.2", - "mqtt": "^4.2.6", - "serialport": "^9.0.0", - "total.js": "^3.4.5", "bitwise": "^2.1.0", - "log4js": "^6.3.0" + "easy-crc": "0.0.2", + "jsmodbus": "^4.0.6", + "log4js": "^6.3.0", + "mqtt": "^4.2.6", + "nodemailer": "^6.9.7", + "serialport": "^9.2.8", + "total.js": "^3.4.13" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/saved_data/modbus_settings b/saved_data/modbus_settings deleted file mode 100644 index 61c37a3..0000000 --- a/saved_data/modbus_settings +++ /dev/null @@ -1,135 +0,0 @@ -{ - "config": { - "isRunning": false, - "debug": true, - "timeoutTime": 4000, - "msgWaitTime": 20000, - "port": "/dev/ttymxc1", - "port_options": "stty -F /dev/ttymxc1 9600 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke" - }, - "private": { - "errBuffer": [], - "tbBuffer": [], - "device_index": 0, - "cmd_index": 0, - "devices": [{ - "name": "Elektrometer 1", - "tb_name": "", - "type": "EM340", - "address": 1, - "data": [], - "cmd": [], - "timeoutcount": 0, - "status": "virtual" - }], - "cmd_tables": [{ - "type": "EM340", - "cmd": [{ - "name": "Voltage L1", - "tb_name": "Phase_1_voltage", - "register": 0, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Voltage L2", - "tb_name": "Phase_2_voltage", - "register": 2, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Voltage L3", - "tb_name": "Phase_3_voltage", - "register": 4, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Current L1", - "tb_name": "Phase_1_current", - "register": 12, - "size": 2, - "multiplier": 0.001 - }, - { - "name": "Current L2", - "tb_name": "Phase_2_current", - "register": 14, - "size": 2, - "multiplier": 0.001 - }, - { - "name": "Current L3", - "tb_name": "Phase_3_current", - "register": 16, - "size": 2, - "multiplier": 0.001 - }, - { - "name": "Power L1", - "tb_name": "Phase_1_power", - "register": 18, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Power L2", - "tb_name": "Phase_2_power", - "register": 20, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Power L3", - "tb_name": "Phase_3_power", - "register": 22, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Power tot", - "tb_name": "total_power", - "register": 40, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "Energy in", - "tb_name": "total_energy", - "register": 52, - "size": 2, - "multiplier": 0.1 - }, - { - "name": "PowF L1", - "tb_name": "Phase_1_pow_factor", - "register": 46, - "size": 1, - "multiplier": 0.001 - }, - { - "name": "PowF L2", - "tb_name": "Phase_2_pow_factor", - "register": 47, - "size": 1, - "multiplier": 0.001 - }, - { - "name": "PowF L3", - "tb_name": "Phase_3_pow_factor", - "register": 48, - "size": 1, - "multiplier": 0.001 - }, - { - "name": "PowF", - "tb_name": "power_factor", - "register": 49, - "size": 1, - "multiplier": 0.001 - } - ] - }] - } -}