From 86619fbcff6e45630bf2a897565fe6444a8de4ee Mon Sep 17 00:00:00 2001 From: rasta5man Date: Sat, 13 Apr 2024 20:29:31 +0200 Subject: [PATCH 1/9] 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 - } - ] - }] - } -} From ac2ccc1c618b37a61975666b74fd26675b1f64be Mon Sep 17 00:00:00 2001 From: rasta5man Date: Tue, 7 May 2024 14:11:40 +0200 Subject: [PATCH 2/9] senica add rebuild tasks at 11 on tuesday and saturday --- flow/dido_controller.js | 15 +- flow/helper/DataToTbHandler.js | 324 ++++++++++++++++----------------- 2 files changed, 171 insertions(+), 168 deletions(-) diff --git a/flow/dido_controller.js b/flow/dido_controller.js index 8b5a7b7..044a38f 100644 --- a/flow/dido_controller.js +++ b/flow/dido_controller.js @@ -311,16 +311,19 @@ exports.install = function(instance) { }, time); } - - // we ensure, all tasks will be rebuild every day at 11. To set correct switch off and on times + // TODO: FIND BETTER SOLUTION, THAN REBUILDING TASKS + // we ensure, all tasks will be rebuild twice a week on tuesday or saturday 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) + const day = d.getDay(); + + if((day === 2 || day === 6) && h === 11) { instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"}); + monitor.info("Task rebuilt at 11 o'clock, tuesday, saturday"); } } sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000); @@ -1465,13 +1468,13 @@ exports.install = function(instance) { 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}); + instance.send(instanceSendTo.cmd_manager, {sender: "dido_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; + const tbname = relaysData[lineOnSameBraker].tbname; sendTelemetry(values, tbname); delete values[type]; @@ -1909,4 +1912,4 @@ exports.install = function(instance) { // } // } // ] -// } \ No newline at end of file +// } diff --git a/flow/helper/DataToTbHandler.js b/flow/helper/DataToTbHandler.js index 15b0c0a..8fff312 100644 --- a/flow/helper/DataToTbHandler.js +++ b/flow/helper/DataToTbHandler.js @@ -1,163 +1,163 @@ -class DataToTbHandler -{ - constructor(index) { - this.index = index; - - this.previousValues = {}; - this.debug = false; - this.messageCounter = 0; - - this.sender = ""; - } - - dump() - { - console.log("----------------------------"); - console.log("previousValues", this.previousValues); - console.log("----------------------------"); - } - - setSender(sender) - { - this.sender = sender; - } - - isEmptyObject( obj ) { - for ( var name in obj ) { - return false; - } - return true; - } - - sendToTb(dataToTb, instance) - { - - if(!FLOW.OMS_brokerready) - { - return dataToTb; - } - - let keys = Object.keys(dataToTb); - - if(keys.length == 0) - { - if(this.debug) console.log("sendToTb received epty object", dataToTb); - return; - } - - - let tbname = keys[0]; - let ts; - - let arrayOfValues = dataToTb[tbname]; - let arrayOfValuesToSend = []; - - for(let i = 0; i < arrayOfValues.length; i++) - { - ts = arrayOfValues[i].ts; - - //console.log("sendToTb------------>before", arrayOfValues[i].values, tbname); - - let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values); - - //console.log("sendToTb------------>after", values); - - if(!this.isEmptyObject(values)) - { - arrayOfValuesToSend.push({ts: ts, values: values}); - } - } - - if(arrayOfValuesToSend.length == 0) - { - //if(this.debug) console.log("data not sent - empty array"); - return; - } - - /* - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - */ - - this.messageCounter++; - - let dataToTbModified = { - [tbname]: arrayOfValuesToSend - } - - //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance); - if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend); - - instance.send(this.index, dataToTbModified); - } - - getDiffTimestamp(key) - { - let seconds = 60*60;//1h - //seconds = 1;//for testing - - //TODO set different value for given key!!! - //if(key == "status") seconds = 2*60*60;//2h - - let timestampDiffToRemoveKey = seconds*1000; - - return timestampDiffToRemoveKey; - } - - prepareValuesForTb(tbname, timestamp, values) - { - let keys = Object.keys(values); - if(!this.previousValues.hasOwnProperty(tbname)) - { - this.previousValues[tbname] = {}; - } - - //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values); - - for(let i = 0; i < keys.length; i++) - { - let key = keys[i]; - let value = values[key]; - - if(!this.previousValues[tbname].hasOwnProperty(key)) - { - this.previousValues[tbname][key] = {ts: timestamp, value: value}; - continue; - } - - if(this.previousValues[tbname][key].value === value) - { - let diff = timestamp - this.previousValues[tbname][key].ts; - - let timestampDiffToRemoveKey = this.getDiffTimestamp(key); - if(diff > timestampDiffToRemoveKey) - { - this.previousValues[tbname][key].ts = Date.now(); - //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter); - - } - else - { - delete values[key]; - //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey); - } - } - else - { - this.previousValues[tbname][key].value = value; - this.previousValues[tbname][key].ts = timestamp; - } - - } - - return values; - } -} - +class DataToTbHandler +{ + constructor(index) { + this.index = index; + + this.previousValues = {}; + this.debug = false; + this.messageCounter = 0; + + this.sender = ""; + } + + dump() + { + console.log("----------------------------"); + console.log("previousValues", this.previousValues); + console.log("----------------------------"); + } + + setSender(sender) + { + this.sender = sender; + } + + isEmptyObject( obj ) { + for ( var name in obj ) { + return false; + } + return true; + } + + sendToTb(dataToTb, instance) + { + + if(!FLOW.OMS_brokerready) + { + return dataToTb; + } + + let keys = Object.keys(dataToTb); + + if(keys.length == 0) + { + if(this.debug) console.log("sendToTb received epty object", dataToTb); + return; + } + + + let tbname = keys[0]; + let ts; + + let arrayOfValues = dataToTb[tbname]; + let arrayOfValuesToSend = []; + + for(let i = 0; i < arrayOfValues.length; i++) + { + ts = arrayOfValues[i].ts; + + //console.log("sendToTb------------>before", arrayOfValues[i].values, tbname); + + let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values); + + //console.log("sendToTb------------>after", values); + + if(!this.isEmptyObject(values)) + { + arrayOfValuesToSend.push({ts: ts, values: values}); + } + } + + if(arrayOfValuesToSend.length == 0) + { + //if(this.debug) console.log("data not sent - empty array"); + return; + } + + /* + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + */ + + this.messageCounter++; + + let dataToTbModified = { + [tbname]: arrayOfValuesToSend + } + + //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance); + if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend); + + instance.send(this.index, dataToTbModified); + } + + getDiffTimestamp(key) + { + let seconds = 60*60;//1h + //seconds = 1;//for testing + + //TODO set different value for given key!!! + //if(key == "status") seconds = 2*60*60;//2h + + let timestampDiffToRemoveKey = seconds*1000; + + return timestampDiffToRemoveKey; + } + + prepareValuesForTb(tbname, timestamp, values) + { + let keys = Object.keys(values); + if(!this.previousValues.hasOwnProperty(tbname)) + { + this.previousValues[tbname] = {}; + } + + //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values); + + for(let i = 0; i < keys.length; i++) + { + let key = keys[i]; + let value = values[key]; + + if(!this.previousValues[tbname].hasOwnProperty(key)) + { + this.previousValues[tbname][key] = {ts: timestamp, value: value}; + continue; + } + + if(this.previousValues[tbname][key].value === value) + { + let diff = timestamp - this.previousValues[tbname][key].ts; + + let timestampDiffToRemoveKey = this.getDiffTimestamp(key); + if(diff > timestampDiffToRemoveKey) + { + this.previousValues[tbname][key].ts = Date.now(); + //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter); + + } + else + { + delete values[key]; + //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey); + } + } + else + { + this.previousValues[tbname][key].value = value; + this.previousValues[tbname][key].ts = timestamp; + } + + } + + return values; + } +} + module.exports = DataToTbHandler; \ No newline at end of file From 86c7b3a942d82b4aefeacbef174736a69bd7a3f1 Mon Sep 17 00:00:00 2001 From: rasta5man Date: Tue, 7 May 2024 16:28:43 +0200 Subject: [PATCH 3/9] add buildTasks function to dido_controller and handle 7 lines with state_of_braker --- flow/cmd_manager.js | 7965 +++++++++++++++++++-------------------- flow/dido_controller.js | 3860 +++++++++---------- flow/modbus_reader.js | 22 +- 3 files changed, 5940 insertions(+), 5907 deletions(-) diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index c1efd18..7f77d20 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -1,3983 +1,3982 @@ -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; - -} - - - - +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.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"|| entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") + { + if(method == "set_command") + { + + //let command = data.params.command; + let value = data.params.payload.value; + + if(command == "dimming") + { + + 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/dido_controller.js b/flow/dido_controller.js index 044a38f..60e3976 100644 --- a/flow/dido_controller.js +++ b/flow/dido_controller.js @@ -1,1915 +1,1945 @@ -exports.id = 'dido_controller'; -exports.title = 'DIDO_Controller'; -exports.version = '2.0.0'; -exports.group = 'Worksys'; -exports.color = '#2134B0'; -exports.input = 3; -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 -*/ - - -//globals -//FIRMWARE version -FLOW.OMS_edge_fw_version = "2023-10-18";//rok-mesiac-den -FLOW.OMS_edgeName = ""; -FLOW.OMS_maintenance_mode = false; - -//dynamic values -FLOW.OMS_masterNodeIsResponding = true; //cmd_manager -//FLOW.OMS_brokerready = false //wsmqttpublish -FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer - -//see loadSettings() in cmd_manager -FLOW.OMS_language = "en";//cmd_manager -FLOW.OMS_rvo_name = "";//cmd_manager -FLOW.OMS_rvo_tbname = "";//relaysData -FLOW.OMS_temperature_adress = "";//cmd_manager -//----------------------------------------------- - -let alarmStatus = "OFF"; - -const instanceSendTo = { - debug: 0, - tb: 1, - cmd_manager: 2 -} - -var log4js = require("log4js"); -var path = require('path'); - -log4js.configure({ - appenders: { - errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') }, - monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') }, - console: { type: 'console' } - }, - categories: { - errLogs: { appenders: ['console', 'errLogs'], level: 'error' }, - monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' }, - //another: { appenders: ['console'], level: 'trace' }, - default: { appenders: ['console'], level: 'trace' } - } -}); - -const errLogger = log4js.getLogger("errLogs"); -const logger = log4js.getLogger(); -const monitor = log4js.getLogger("monitorLogs"); - -//console.log(path.join(__dirname, 'err.txt', "-----------------------------")); - -/* -process.on('uncaughtException', function (err) { - - errLogger.error('uncaughtException:', err.message) - errLogger.error(err.stack); - - //process.exit(1); -}) -*/ - -//USAGE -//logger.debug("text") -//monitor.info('info'); -//errLogger.error("some error"); - -exports.install = function(instance) { - - process.on('uncaughtException', function (err) { - - //TODO send to service - - errLogger.error('uncaughtException:', err.message) - errLogger.error(err.stack); - - errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error"); - - //process.exit(1); - }) - - let previousValues = {temperature: 0}; - let rsPortReceivedData = []; - - let twilight_sensor_interval = 5;//minutes - let twilight_sensor = []; - const twilight_sensor_array = []; - let twilightError = false; - - let edgeName = ""; - - monitor.info("DI_DO_Relay_Controller installed"); - - //key is PIN number , line: 0 = RVO - /* - let conversionTable = { - "1": {tbname: "", type: "state_of_main_switch", "line": 0}, //state_of_main_switch pin1 - "2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2 - "3": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha auto = pin3 - "4": {tbname: "", type: "power_supply", "line": 0}, - "5": {tbname: "", type: "battery", "line": 0}, - "6": {tbname: "", type: "door_condition", "line": 0}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open - "8": {tbname: "", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on - "9": {tbname: "", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on - "10": {tbname: "", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on - "11": {tbname: "", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on - "12": {tbname: "", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on - "13": {tbname: "", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on - "16": {tbname: "", type: "twilight_sensor", "line": 0}, // twilight_sensor = pin16 - }; - */ - - const dbPins = TABLE("pins"); - let pinsData = {};//key is pin - - const dbRelays = TABLE("relays"); - let relaysData = {};//key is line - - //status for calculating Statecodes - let deviceStatuses = {};//key is device name: temperature,.... - deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič - deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód - deviceStatuses["door_condition"] = "closed";//Dverový kontakt - deviceStatuses["em"] = "OK";//elektromer rvo - deviceStatuses["temperature"] = "OK";//templomer - deviceStatuses["battery"] = "OK";//Batéria - deviceStatuses["power_supply"] = "OK";//Zdroj - deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding - deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze - - deviceStatuses["state_of_breaker"] = {};//"Off";//Istič - deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač - deviceStatuses["twilight_sensor"] = "OK"; //lux sensor - - /* - dbRelays.on('change', function(doc, old) { - console.log("'DI_DO_Controller - dbRelays.on('change'"); - instance.send(instanceSendTo.cmd_manager, "reload_relays"); - }); - */ - - const SerialPort = require('serialport'); - const WebSocket = require('ws'); - - let ws = null; - let rsPort = null; - - //const { exec } = require('child_process'); - const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js'); - const { bytesToInt, resizeArray } = require('./helper/utils'); - const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); - const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js'); - const bitwise = require('bitwise'); - - const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js'); - const errorHandler = new ErrorToServiceHandler(); - - //let useTurnOffCounter = false; - //let turnOffCounter = 0; - let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine - if(controller_type == "") controller_type = "lm"; - - console.log(exports.title, "controller type: ", controller_type); - - async function loadAllDb() - { - let responsePins = await promisifyBuilder(dbPins.find()); - pinsData = makeMapFromDbResult(responsePins, "pin"); - - let responseRelays = await promisifyBuilder(dbRelays.find()); - relaysData = makeMapFromDbResult(responseRelays, "line"); - - FLOW.OMS_rvo_tbname = relaysData[0].tbname; - - if(controller_type === "lm") - { - handleRsPort(); - } - else if(controller_type === "unipi") - { - handleWebSocket(); - } - else { - errLogger.debug("UNKNOWN controller_type:", controller_type); - } - } - - - function initialSetting() - { - //force turn off relays & set tbname - let keys = Object.keys(pinsData); - for(let i = 0; i < keys.length; i++) - { - let key = keys[i]; - let line = pinsData[key].line; - - if(line != undefined) - { - if(relaysData[line] != undefined) - { - pinsData[key].tbname = relaysData[line].tbname; - - relaysData[line].contactor = 0; - } - else - { - errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line); - - //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", instanceSendTo.tb, instance, null ); - sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", instanceSendTo.tb, instance ); - } - } - - if(pinsData[key].type == "state_of_contactor") - { - - let pin = key - 1; - if(controller_type === "unipi") pin = key; - - //this will modify database - let forceTurnOff = true; - turnOffLine(line, pin, forceTurnOff, "turn off on startup"); - } - } - - //report RVO version relaysData[0].tbname; - let values = {}; - values["edge_fw_version"] = FLOW.OMS_edge_fw_version; - values["maintenance_mode"] = FLOW.OMS_maintenance_mode; - values["status"] = "OK"; - - edgeName = relaysData[0].tbname; - FLOW.OMS_edgeName = edgeName; - - dataToTb = { - [edgeName]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - instance.send(instanceSendTo.tb, dataToTb); - - let time = 3*1000; - setTimeout(function(){ - 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); - } - - // TODO: FIND BETTER SOLUTION, THAN REBUILDING TASKS - // we ensure, all tasks will be rebuild twice a week on tuesday or saturday at 11. To set correct switch off and on times - let sendRebuildTasksAt11 = null; - const checkIf11Oclock = () => - { - const d = new Date(); - const h = d.getHours(); - const day = d.getDay(); - - if((day === 2 || day === 6) && h === 11) - { - instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"}); - monitor.info("Task rebuilt at 11 o'clock, tuesday, saturday"); - } - } - sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000); - - - function handleRsPort() - { - //TODO build according to pins!!! - //! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0") - const setRSPortData = [0xAA,6,6,6,6,6,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,10,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,15,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0]; - rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false }); - - rsPort.on('error', function(err) { - logger.debug("rsPort opened error - failed", err.message); - instance.send(instanceSendTo.debug, err.message); - - errorHandler.sendMessageToService( exports.title + " rsPort opened error - failed: " + err.message); - }) - - rsPort.on('open', async function() { - - await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) { - - //set port - rsPort.write(Buffer.from(setRSPortData), function(err) { - monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)"); - - turnOffAlarm(); - - //useTurnOffCounter = true; - //turnOffCounter = relaysData.length - 1; - - initialSetting(); - }) - - }).catch(function (reason) { - //instance.send(instanceSendTo.debug, exports.title + " runSyncExec - promise rejected:" + reason); - errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason); - - errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason); - }); - - }); - - - rsPort.on('data', function (data){ - - rsPortReceivedData = [...rsPortReceivedData, ...data]; - - if (rsPortReceivedData[0] != 85) { - rsPortReceivedData = []; - return; - } - - let l = rsPortReceivedData.length; - - if (l < 4 ) return; - - if (l > 4 ) { - - // if array length is greater than 4, we take first 4 byte and do the logic, second 4 bytes, do the logic and so on - let i, j, temparray, chunk = 4; - for ( i = 0, j = l; i < j; i += chunk ) { - temparray = rsPortReceivedData.slice(i, i + chunk); - - if ( temparray.length < 4 ){ - rsPortReceivedData = [...temparray]; - return; - } - - switchLogic(temparray); - } - - rsPortReceivedData = []; - return; - } - - switchLogic(rsPortReceivedData); - - rsPortReceivedData = []; - - }); - - rsPort.on("close", () => { - rsPort.close(); - }) - - rsPort.open(); - - } - - - function handleWebSocket() { - - //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() { - - instance.send(0, exports.title + " running"); - turnOffAlarm(); - - // useTurnOffCounter = true; - // turnOffCounter = relaysData.length - 1; - initialSetting(); - ws.send(JSON.stringify({"cmd":"all"})); - - // 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 -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_07', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_08', -// debounce: 50, -// counter: 0, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, - ws.onmessage = function(data) { - - data = JSON.parse(data.data); - - // data comes in array except of "temperature" ==> it comes as an object - if(!Array.isArray(data)) - { - let value = data['value']; - - // temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB - if(Math.abs(previousValues["temperature"] - value) > 0.21 ) - { - const dataToTb = { - [FLOW.OMS_rvo_tbname]: [ - { - "ts": Date.now(), - "values": {temperature: value} - } - ] - }; - - deviceStatuses["temperature"] = "OK"; - previousValues["temperature"] = value; - instance.send(instanceSendTo.tb, dataToTb); - } - return; - } - - data.map(item => { - - let value = item['value']; - let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01" - - if (pin == undefined) return; - switchLogic(pin, value); - }) - } - - - ws.on('error', (err) => { - instance.send(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..."); - setTimeout(handleWebSocket, 1000); - } - } - - // ! do we need requests every minute ??? - // const startRequests = () => { - // console.log("startRequest function called"); - // start = setInterval(() => { - // // console.log("data from evok requested"); - // ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"})); - // // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]})); - // }, 150000) - // } - - - instance.on("close", () => { - if(rsPort) rsPort.close(); - if(ws) ws.close(); - clearInterval(sendRebuildTasksAt11); - }) - - loadAllDb(); - - function getPin(line) - { - //conversionTable - let keys = Object.keys(pinsData); - for(let i = 0; i < keys.length; i++) - { - let key = keys[i]; - - if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line) - { - if(rsPort) return key - 1; - if(ws) return key; - } - } - - logger.debug("no pin detected"); - - return null; - } - - - function turnOnAlarm() - { - if(FLOW.OMS_maintenance_mode) return; - - alarmStatus = "ON"; - - if(rsPort) - { - let arr = [0x55]; - arr.push( 13 ); - arr.push( 0 ); - arr.push( 1 ); - - rsPort.write(Buffer.from(arr), function(err) { - logger.debug("sirena zapnuta"); - }); - } - else if(ws) - { - let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1}; - ws.send(JSON.stringify(cmd)); - logger.debug("sirena zapnuta"); - } - } - - - function turnOffAlarm() - { - alarmStatus = "OFF"; - - if(rsPort) - { - let arr = [0x55]; - arr.push( 13 ); - arr.push( 0 ); - arr.push( 0 ); - - rsPort.write(Buffer.from(arr), function(err) { - logger.debug("sirena vypnuta"); - }); - } - else if(ws) - { - let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0}; - ws.send(JSON.stringify(cmd)); - logger.debug("sirena vypnuta"); - } - } - - - function reportLineStatus(line) - { - //Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false). - - let tbname = relaysData[line].tbname; - - let bits = []; - - if(deviceStatuses["state_of_breaker"][line] == "On") - { - bits.push(0); - } - else bits.push(1); - - if(deviceStatuses["state_of_contactor"][line] == "On") - { - bits.push(0); - } - else bits.push(1); - - resizeArray(bits, 8, 0); - - let byte = bitwise.byte.write(bits.reverse()); - - //console.log("line", line, bits, byte); - - let values = { - statecode: byte - } - - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - //console.log(values); - - instance.send(instanceSendTo.tb, dataToTb); - } - - - function turnOnLine(line, pin, force, info) - { - - instance.send(instanceSendTo.debug, "turn on line " + line ); - if(force == undefined) force = false; - - if(line == 0) - { - if(alarmStatus == "ON") turnOffAlarm(); - FLOW.OMS_maintenance_mode = true; - - let values = {}; - values["statecode"] = calculateStateCode(); - values["power_mode"] = "maintenance"; - let tbname = relaysData[line].tbname; - sendTelemetry(values, tbname); - - monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info); - - return; - } - - if( pin === undefined) pin = getPin(line); - - monitor.info("turnOnLine (line, pin, force)", line, pin, force, info); - - if( pin === undefined) - { - monitor.info("pin is undefined!", line); - return; - } - - - if(!force) - { - if(relaysData[line].contactor == 1) - { - instance.send(instanceSendTo.debug, "line is already on " + line ); - logger.debug("turnOnLine: line is already on: ", line); - - return; - } - } - - // if(!rsPort.isOpen && !ws) - if(!rsPort && !ws) - { - errLogger.error("di do controller - port or websocket is not opened"); - return; - } - - if(rsPort) - { - let arr = [0x55]; - arr.push( pin ); - arr.push( 0 ); - arr.push( 1 ); - - rsPort.write(Buffer.from(arr), function(err) { - if(err === undefined) - { - console.log("turnONLine zapisal do rsPortu", line, arr); - switchLogic(arr); - } - else - { - monitor.info("turnOnLine WRITE error", err); - } - - }); - - } - else if(ws) - { - console.log("turnONLine pin (relay)", pin); - //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method - let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1}; - ws.send(JSON.stringify(cmd)); - //switchLogic(pin, 1) - } - } - - - function turnOffLine(line, pin, force, info) - { - if(force == undefined) force = false; - - if(line == 0) - { - FLOW.OMS_maintenance_mode = false; - - let values = {}; - values["statecode"] = calculateStateCode(); - values["power_mode"] = "automatic"; - let tbname = relaysData[line].tbname; - sendTelemetry(values, tbname); - - return; - } - - if( pin === undefined) pin = getPin(line); - - monitor.info("turnOffLine (line, pin, force)", line, pin, force, info); - - if( pin === undefined) - { - errLogger.error("pin is undefined!", line); - return; - } - - if(!force) - { - if(relaysData[line].contactor == 0) - { - instance.send(instanceSendTo.debug, "line is already off " + line ); - logger.debug("turnOffLine: line already off:", line); - - return; - } - } - - // if(!rsPort.isOpen && !ws) - if(!rsPort && !ws) - { - errLogger.error("di do controller - port or websocket is not opened"); - return; - } - - if(rsPort) - { - let arr = [0x55]; - arr.push( pin ); - arr.push( 0 ); - arr.push( 0 ); - - rsPort.write(Buffer.from(arr), function(err) { - if(err === undefined) - { - console.log("turnOffLine zapisal do rsPort-u", line, arr); - switchLogic(arr); - } - else - { - monitor.info("turnOffLine WRITE error", err); - } - - }); - - } - else if(ws) - { - //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method - //monitor.info("turnOffLine pin (relay)", pin); - let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0}; - ws.send(JSON.stringify(cmd)); - //switchLogic(pin, 0) - } - - } - - - //data from modbus_reader or temperature sensor or twilight sensor or other modbus device - instance.on("0", flowdata => { - - if(!flowdata.data instanceof Object) return; - - // console.log('***********************', flowdata.data) - instance.send(instanceSendTo.debug, flowdata.data); - - // we handle nok status from modbus_reader component and thermometer - if(flowdata.data?.status) - { - const status = flowdata.data.status; - if(status == "NOK-twilight_sensor") - { - deviceStatuses["twilight_sensor"] = "NOK"; - } - else if(status == "NOK-em340" || status == "NOK-em111") - { - deviceStatuses["em"] = "NOK"; - } - else if(status == "NOK-thermometer") - { - deviceStatuses["temperature"] = "NOK"; - } - 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(obj)){ - - rsPort.write(Buffer.from(obj), function(err) { - switchLogic(obj); - - instance.send(instanceSendTo.debug, {"WRITE":obj} ); - }); - } - }) - - - function calculateStateCode() - { - - let bytes = []; - let bits = []; - - //Hlavný istič - state_of_main_switch - if(deviceStatuses["state_of_main_switch"] == "On") - { - bits.push(0); - } - else if(deviceStatuses["state_of_main_switch"] == "Off") - { - bits.push(1); - } - - //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY - if(!FLOW.OMS_maintenance_mode) - { - if(deviceStatuses["rotary_switch_state"] == "Manual") - { - bits.push(0); - bits.push(1); - } - - if(deviceStatuses["rotary_switch_state"] == "Automatic") - { - bits.push(0); - bits.push(0); - } - - if(deviceStatuses["rotary_switch_state"] == "Off") - { - bits.push(1); - bits.push(0); - } - } - else{ - bits.push(1); - bits.push(1); - } - - //Dverový kontakt - if(deviceStatuses["door_condition"] == "closed") - { - bits.push(0); - } - else - { - bits.push(1); - } - - //EM - if(deviceStatuses["em"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - //Teplomer - if(deviceStatuses["temperature"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - //Batéria - if(deviceStatuses["battery"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - //Zdroj - if(deviceStatuses["power_supply"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - //MN - if(deviceStatuses["master_node"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - //výpadok napätia na fáze - if(deviceStatuses["no_voltage"] == "NOK") - { - bits.push(1); - } - else - { - bits.push(0); - } - - 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); - - return byte; - } - - - function checkFinalRVOStatus() { - - // we check if any of these pins values are 0 --> it means status RVO is "NOK" - // pinIndex 6 is door_condition - if open in maintenance mode - status = OK - - //set RVO state - - let status = "OK"; - - if(deviceStatuses["em"] == "NOK") - { - 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"; - } - - //ak teplomer NOK, rvo nok - if(deviceStatuses["temperature"] == "NOK") - { - - let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK"); - if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK"); - - status = "NOK"; - } - - if(status == "OK") - { - let pinIndexes = [1, 4, 6]; - if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05']; - - //console.log('-------- previousValues', previousValues); - - for (const pinIndex of pinIndexes) { - if (previousValues[pinIndex] === 0) { - - if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue; - - let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0"); - if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type); - - status = "NOK"; - - break; - } - } - } - - // battery status. If value is 1 - battery is NOK - if (previousValues[5] === 1) - { - let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery"); - if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery"); - - status = "NOK"; - } - - //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding); - - if(!FLOW.OMS_masterNodeIsResponding) - { - //errLogger.error("Master node is not responding"); - errorHandler.sendMessageToService("Master node is not responding"); - status = "NOK"; - - deviceStatuses["master_node"] = "NOK"; - } - else deviceStatuses["master_node"] = "OK"; - - //console.log("checkFinalRVOStatus", status); - if(FLOW.OMS_no_voltage.size > 0) - { - let writeToFile = errorHandler.processMessage("no voltage detected"); - if(writeToFile) errLogger.error("no voltage detected", FLOW.OMS_no_voltage); - - status = "NOK"; - - deviceStatuses["no_voltage"] = "NOK"; - } - else deviceStatuses["no_voltage"] = "OK"; - - if(status == "NOK") - { - sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname); - - return false; - } - - return true; - } - - - // 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, twilight; - - //data from rsPort - if(args.length == 1) - { - pinIndex = args[0][1] + 1; - if (pinIndex === 17) pinIndex--; - newPinValue = args[0][3]; - twilight = args[0][2]; - } - //data from websocket - else - { - pinIndex = args[0]; - newPinValue = args[1]; - } - - let obj = pinsData[pinIndex]; - - if(obj == undefined) - { - previousValues[pinIndex] = newPinValue; - return; - } - - let type = obj.type; - let line = obj.line; - let tbname = obj.tbname; - - //default value - let value = "On"; - if(newPinValue === 0) value = "Off"; - - //Hlavný istič - //! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri - //! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition' - if(type === "!!!state_of_main_switch") - { - if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) - { - sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); - values["status"] = "NOK"; - - deviceStatuses["state_of_main_switch"] = "Off"; - } - else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) - { - sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); - - deviceStatuses["state_of_main_switch"] = "On"; - } - } - - //Prevádzkový mód - if(type == "rotary_switch_state") - { - // combination of these two pins required to get result - let pin2, pin3; - if(pinIndex == 2 || pinIndex == "input1_02") - { - pin2 = newPinValue; - pin3 = previousValues[3] || previousValues["input1_03"]; - - if(pin3 == undefined) - { - previousValues[pinIndex] = newPinValue; - return; - } - } - else if(pinIndex == 3 || pinIndex == "input1_03") - { - pin3 = newPinValue; - pin2 = previousValues[2] || previousValues["input1_02"]; - - if(pin2 == undefined) - { - previousValues[pinIndex] = newPinValue; - return; - } - } - - //console.log('***********************', pin2, pin3) - if (pin2 == 1 && pin3 == 0) value = "Manual"; - if (pin2 == 0 && pin3 == 0) value = "Off"; - if (pin2 == 0 && pin3 == 1) value = "Automatic"; - - deviceStatuses["rotary_switch_state"] = value; - - //automatic - profilu pre nody sa vykonavaju - //ak je spracovany, a automatic - tak ho zapnem - //ak nie je spracovany, iba profil zapisem - - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value}); - - //console.log("rotary_switch_state pin", pin2, pin3, value); - } - //Zdroj - pin 4 - else if (type === "power_supply") - { - if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", instanceSendTo.tb, instance, "power_supply"); - values["status"] = "NOK"; - - deviceStatuses["power_supply"] = "NOK"; - } - else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", instanceSendTo.tb, instance, "power_supply"); - - deviceStatuses["power_supply"] = "OK"; - } - } - //Batéria - pin 5 - else if (type === "battery") - { - if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", instanceSendTo.tb, instance, "battery_level"); - values["status"] = "NOK"; - - deviceStatuses["battery"] = "NOK"; - } - else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", instanceSendTo.tb, instance, "battery_level"); - - deviceStatuses["battery"] = "OK"; - } - } - //Dverový kontakt - pin 6 - //! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch" - //! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition' - else if(type == "door_condition" || type === "state_of_main_switch") - { - newPinValue === 0 ? value = "open" : value = "closed"; - - if (newPinValue != previousValues[pinIndex]) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", instanceSendTo.tb, instance, "rvo_door"); - //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", instanceSendTo.tb, instance, "rvo_door"); - } - - if (value === "open" && FLOW.OMS_maintenance_mode) - { - sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", instanceSendTo.tb, instance, "rvo_door"); - } - - if (value === "open" && !FLOW.OMS_maintenance_mode) - { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", instanceSendTo.tb, instance, "rvo_door"); - values["status"] = "NOK"; - - //console.log(door_has_been_open_without_permision_alarm_is_on); - - // 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") - { - if(alarmStatus == "ON") turnOffAlarm(); - //turnOffAlarm(); - - sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", instanceSendTo.tb, instance, "rvo_door"); - } - - deviceStatuses["door_condition"] = value; - - } - //lux sensor - else if(type == "twilight_sensor") - { - //! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000. - //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 ); - - 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; - - //modify table relays - dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) { - - builder.callback(function(err, response) { - - /* - if(useTurnOffCounter) - { - turnOffCounter--; - - if(turnOffCounter <= 0) - { - useTurnOffCounter = false; - } - } - */ - - if(err == undefined) - { - - let time = 0; - if(value) time = 1000 * 10;//10 sekund - - let dataChanged = false; - if(relaysData[line].contactor != value) dataChanged = true; - relaysData[line].contactor = value; - - //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles - //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor - - setTimeout(function(){ - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); - }, time); - - reportLineStatus(line); - - - } - else - { - errLogger.error("modify table relays failed", err); - } - - - }); - }); - } - - if(type === "state_of_breaker") - { - - let valueChanged = false; - if(newPinValue != previousValues[pinIndex]) valueChanged = true; - - if(valueChanged) - { - 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: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3}); - - deviceStatuses["state_of_breaker"][line + 3] = value; - reportLineStatus(line + 3); - - values[type] = value; - const tbname = relaysData[lineOnSameBraker].tbname; - sendTelemetry(values, tbname); - - delete values[type]; - } - } - - if(value == "Off") values["status"] = "NOK"; - - deviceStatuses["state_of_breaker"][line] = value; - - reportLineStatus(line); - } - - values[type] = value; - - //if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode(); - - if(pinsData.hasOwnProperty(pinIndex)) - { - let valueChanged = false; - if(newPinValue != previousValues[pinIndex]) - { - valueChanged = true; - //pin was changed - previousValues[pinIndex] = newPinValue; - } - - let result = checkFinalRVOStatus(); - if(!result && line == 0) - { - values["status"] = "NOK"; - } - - if(type == "state_of_contactor") valueChanged = true; - if(type == "rotary_switch_state") valueChanged = true; - if(type === "state_of_breaker") - { - //console.log(type, values, valueChanged); - } - - if(FLOW.OMS_rvo_tbname == "") - { - console.log("FLOW.OMS_rvo_tbname is EMPTY"); - } - - if(FLOW.OMS_rvo_tbname == tbname) - { - values["statecode"] = calculateStateCode(); - //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname); - } - - if(valueChanged) - { - sendTelemetry(values, tbname); - } - - if(type == "rotary_switch_state") - { - if(FLOW.OMS_maintenance_mode) value = "maintenance"; - value = value.toLowerCase(); - - let values = {}; - values["power_mode"] = value; - - sendTelemetry(values, tbname); - } - } - else - { - logger.debug("no pinIndex", pinsData[pinIndex], pinsData); - } - - } - - - function sendTelemetry(values, tbname) - { - let dataToTb = { - [tbname]: [ - { - "ts": Date.now(), - "values": values - } - ] - } - - instance.send(instanceSendTo.tb, dataToTb); - } - -} - - - - -//! incomming data to websocket -// [ -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_08', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_01', -// alias: 'al_lights_kitchen', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_02', -// alias: 'al_lights_bedroom', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_03', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_04', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_05', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_06', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// glob_dev_id: 1, -// modes: [ 'Simple' ], -// value: 0, -// circuit: '1_07', -// pending: false, -// relay_type: 'physical', -// dev: 'relay', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_08', -// debounce: 50, -// counter: 0, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_mode: 'Enabled', -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// dev: 'input', -// modes: [ 'Simple', 'DirectSwitch' ], -// debounce: 50, -// counter: 1, -// value: 1, -// alias: 'al_main_switch', -// mode: 'Simple', -// circuit: '1_01' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 1, -// circuit: '1_02', -// debounce: 50, -// counter: 2, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 1, -// circuit: '1_03', -// debounce: 50, -// counter: 2, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_04', -// debounce: 50, -// counter: 1, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_05', -// debounce: 50, -// counter: 0, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_06', -// debounce: 50, -// counter: 0, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// counter_modes: [ 'Enabled', 'Disabled' ], -// glob_dev_id: 1, -// modes: [ 'Simple', 'DirectSwitch' ], -// value: 0, -// circuit: '1_07', -// debounce: 50, -// counter: 0, -// counter_mode: 'Enabled', -// dev: 'input', -// mode: 'Simple' -// }, -// { -// interval: 3, -// value: 24.5, -// circuit: '28744F7791180257', -// address: '28744F7791180257', -// time: 1631873896.48797, -// typ: 'DS18B20', -// lost: false, -// dev: 'temp' -// }, -// { -// bus: '/dev/i2c-2', -// interval: 3, -// dev: 'owbus', -// scan_interval: 300, -// circuit: '1', -// do_scan: false, -// do_reset: false -// }, -// { -// glob_dev_id: 1, -// last_comm: 0.014672994613647461, -// ver2: '0.1', -// sn: 42, -// circuit: '1', -// model: 'S207', -// dev: 'neuron', -// board_count: 1 -// }, -// { -// circuit: '1_01', -// value: 0, -// glob_dev_id: 1, -// dev: 'wd', -// timeout: 5000, -// was_wd_reset: 0, -// nv_save: 0 -// } -// ] - -//! loaded pins_data --> from LM -// { -// '1': { pin: 1, type: 'state_of_main_switch', line: 0 }, -// '2': { pin: 2, type: 'rotary_switch_state', line: 0 }, -// '3': { pin: 3, type: 'rotary_switch_state', line: 0 }, -// '4': { pin: 4, type: 'power_supply', line: 0 }, -// '5': { pin: 5, type: 'battery', line: 0 }, -// '6': { pin: 6, type: 'door_condition', line: 0 }, -// '8': { pin: 8, type: 'state_of_breaker', line: 1 }, -// '9': { pin: 9, type: 'state_of_breaker', line: 2 }, -// '10': { pin: 10, type: 'state_of_breaker', line: 3 }, -// '11': { pin: 11, type: 'state_of_contactor', line: 1 }, -// '12': { pin: 12, type: 'state_of_contactor', line: 2 }, -// '13': { pin: 13, type: 'state_of_contactor', line: 3 }, -// '16': { pin: 16, type: 'twilight_sensor', line: 0 } -// } - -//! pins.table --> from LM -// pin:number|type:string|line:number -// *|1|state_of_main_switch|0|........... -// *|2|rotary_switch_state|0|........... -// *|3|rotary_switch_state|0|........... -// *|4|power_supply|0|........... -// *|5|battery|0|........... -// *|6|door_condition|0|........... -// *|8|state_of_breaker|1|........... -// *|9|state_of_breaker|2|........... -// *|10|state_of_breaker|3|........... -// *|11|state_of_contactor|1|........... -// *|12|state_of_contactor|2|........... -// *|13|state_of_contactor|3|........... -// *|16|twilight_sensor|0|........... - -//! pins.table --> from UNIPI -// pin:string|type:string|line:number -// *|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 -// { -// '16': { pin: '16', type: 'twilight_sensor', line: 0 }, -// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 }, -// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 }, -// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 }, -// al_power: { pin: 'al_power', type: 'power_supply', line: 0 }, -// al_battery: { pin: 'al_battery', type: 'battery', line: 0 }, -// al_door: { pin: 'al_door', type: 'door_condition', line: 0 }, -// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 }, -// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 }, -// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 }, -// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 }, -// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 }, -// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 }, -// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 }, -// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 }, -// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', line: 0 } -// } - - -//! relays_data -// { -// '0': { -// line: 0, -// tbname: 'KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV', -// contactor: 1, -// profile: '' -// }, -// '1': { -// line: 1, -// tbname: 'RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O', -// contactor: 0, -// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' -// }, -// '2': { -// line: 2, -// tbname: 'dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7', -// contactor: 0, -// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' -// }, -// '3': { -// line: 3, -// tbname: 'vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V', -// contactor: 0, -// profile: '{"intervals":[{"value":0,"end_time":"20:30","start_time":"13:00"},{"value":1,"end_time":"00:10","start_time":"20:30"},{"value":0,"end_time":"13:00","start_time":"05:40"},{"value":1,"end_time":"05:40","start_time":"00:10"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' -// } -// } - - - - - -// { -// "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": "" -// } -// } -// } -// ] -// } +exports.id = 'dido_controller'; +exports.title = 'DIDO_Controller'; +exports.version = '2.0.0'; +exports.group = 'Worksys'; +exports.color = '#2134B0'; +exports.input = 3; +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 +*/ + + +//globals +//FIRMWARE version +FLOW.OMS_edge_fw_version = "2023-10-18";//rok-mesiac-den +FLOW.OMS_edgeName = ""; +FLOW.OMS_maintenance_mode = false; + +//dynamic values +FLOW.OMS_masterNodeIsResponding = true; //cmd_manager +//FLOW.OMS_brokerready = false //wsmqttpublish +FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer + +//see loadSettings() in cmd_manager +FLOW.OMS_language = "en";//cmd_manager +FLOW.OMS_rvo_name = "";//cmd_manager +FLOW.OMS_rvo_tbname = "";//relaysData +FLOW.OMS_temperature_adress = "";//cmd_manager +//----------------------------------------------- + +let alarmStatus = "OFF"; + +const instanceSendTo = { + debug: 0, + tb: 1, + cmd_manager: 2 +} + +var log4js = require("log4js"); +var path = require('path'); + +log4js.configure({ + appenders: { + errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') }, + monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') }, + console: { type: 'console' } + }, + categories: { + errLogs: { appenders: ['console', 'errLogs'], level: 'error' }, + monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' }, + //another: { appenders: ['console'], level: 'trace' }, + default: { appenders: ['console'], level: 'trace' } + } +}); + +const errLogger = log4js.getLogger("errLogs"); +const logger = log4js.getLogger(); +const monitor = log4js.getLogger("monitorLogs"); + +//console.log(path.join(__dirname, 'err.txt', "-----------------------------")); + +/* +process.on('uncaughtException', function (err) { + + errLogger.error('uncaughtException:', err.message) + errLogger.error(err.stack); + + //process.exit(1); +}) +*/ + +//USAGE +//logger.debug("text") +//monitor.info('info'); +//errLogger.error("some error"); + +exports.install = function(instance) { + + process.on('uncaughtException', function (err) { + + //TODO send to service + + errLogger.error('uncaughtException:', err.message) + errLogger.error(err.stack); + + errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error"); + + //process.exit(1); + }) + + let previousValues = {temperature: 0}; + let rsPortReceivedData = []; + + let twilight_sensor_interval = 5;//minutes + let twilight_sensor = []; + const twilight_sensor_array = []; + let twilightError = false; + + let edgeName = ""; + + monitor.info("DI_DO_Relay_Controller installed"); + + //key is PIN number , line: 0 = RVO + /* + let conversionTable = { + "1": {tbname: "", type: "state_of_main_switch", "line": 0}, //state_of_main_switch pin1 + "2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2 + "3": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha auto = pin3 + "4": {tbname: "", type: "power_supply", "line": 0}, + "5": {tbname: "", type: "battery", "line": 0}, + "6": {tbname: "", type: "door_condition", "line": 0}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open + "8": {tbname: "", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on + "9": {tbname: "", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on + "10": {tbname: "", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on + "11": {tbname: "", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on + "12": {tbname: "", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on + "13": {tbname: "", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on + "16": {tbname: "", type: "twilight_sensor", "line": 0}, // twilight_sensor = pin16 + }; + */ + + const dbPins = TABLE("pins"); + let pinsData = {};//key is pin + + const dbRelays = TABLE("relays"); + let relaysData = {};//key is line + + //status for calculating Statecodes + let deviceStatuses = {};//key is device name: temperature,.... + deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič + deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód + deviceStatuses["door_condition"] = "closed";//Dverový kontakt + deviceStatuses["em"] = "OK";//elektromer rvo + deviceStatuses["temperature"] = "OK";//templomer + deviceStatuses["battery"] = "OK";//Batéria + deviceStatuses["power_supply"] = "OK";//Zdroj + deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding + deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze + + deviceStatuses["state_of_breaker"] = {};//"Off";//Istič + deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač + deviceStatuses["twilight_sensor"] = "OK"; //lux sensor + + /* + dbRelays.on('change', function(doc, old) { + console.log("'DI_DO_Controller - dbRelays.on('change'"); + instance.send(instanceSendTo.cmd_manager, "reload_relays"); + }); + */ + + const SerialPort = require('serialport'); + const WebSocket = require('ws'); + + let ws = null; + let rsPort = null; + + //const { exec } = require('child_process'); + const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js'); + const { bytesToInt, resizeArray } = require('./helper/utils'); + const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js'); + const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js'); + const bitwise = require('bitwise'); + + const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js'); + const errorHandler = new ErrorToServiceHandler(); + + //let useTurnOffCounter = false; + //let turnOffCounter = 0; + let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine + if(controller_type == "") controller_type = "lm"; + + console.log(exports.title, "controller type: ", controller_type); + + async function loadAllDb() + { + let responsePins = await promisifyBuilder(dbPins.find()); + pinsData = makeMapFromDbResult(responsePins, "pin"); + + let responseRelays = await promisifyBuilder(dbRelays.find()); + relaysData = makeMapFromDbResult(responseRelays, "line"); + + FLOW.OMS_rvo_tbname = relaysData[0].tbname; + + if(controller_type === "lm") + { + handleRsPort(); + } + else if(controller_type === "unipi") + { + handleWebSocket(); + } + else { + errLogger.debug("UNKNOWN controller_type:", controller_type); + } + } + + + function initialSetting() + { + //force turn off relays & set tbname + let keys = Object.keys(pinsData); + for(let i = 0; i < keys.length; i++) + { + let key = keys[i]; + let line = pinsData[key].line; + + if(line != undefined) + { + if(relaysData[line] != undefined) + { + pinsData[key].tbname = relaysData[line].tbname; + + relaysData[line].contactor = 0; + } + else + { + errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line); + + //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", instanceSendTo.tb, instance, null ); + sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", instanceSendTo.tb, instance ); + } + } + + if(pinsData[key].type == "state_of_contactor") + { + + let pin = key - 1; + if(controller_type === "unipi") pin = key; + + //this will modify database + let forceTurnOff = true; + turnOffLine(line, pin, forceTurnOff, "turn off on startup"); + } + } + + //report RVO version relaysData[0].tbname; + let values = {}; + values["edge_fw_version"] = FLOW.OMS_edge_fw_version; + values["maintenance_mode"] = FLOW.OMS_maintenance_mode; + values["status"] = "OK"; + + edgeName = relaysData[0].tbname; + FLOW.OMS_edgeName = edgeName; + + dataToTb = { + [edgeName]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + instance.send(instanceSendTo.tb, dataToTb); + + let time = 3*1000; + setTimeout(function(){ + 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); + } + + + // TODO: FIND BETTER SOLUTION, THAN REBUILDING TASKS + // we ensure, all tasks will be rebuild twice a week on tuesday or saturday at 11. To set correct switch off and on times + let sendRebuildTasksAt11 = null; + const checkIf11Oclock = () => + { + const d = new Date(); + const h = d.getHours(); + const day = d.getDay(); + + if((day === 2 || day === 6) && h === 11) + { + instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"}); + monitor.info("Task rebuilt at 11 o'clock, tuesday, saturday"); + } + } + sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000); + + + function handleRsPort() + { + //TODO build according to pins!!! + //! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0") + const setRSPortData = [0xAA,6,6,6,6,6,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,10,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,15,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0]; + rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false }); + + rsPort.on('error', function(err) { + logger.debug("rsPort opened error - failed", err.message); + instance.send(instanceSendTo.debug, err.message); + + errorHandler.sendMessageToService( exports.title + " rsPort opened error - failed: " + err.message); + }) + + rsPort.on('open', async function() { + + await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) { + + //set port + rsPort.write(Buffer.from(setRSPortData), function(err) { + monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)"); + + turnOffAlarm(); + + //useTurnOffCounter = true; + //turnOffCounter = relaysData.length - 1; + + initialSetting(); + }) + + }).catch(function (reason) { + //instance.send(instanceSendTo.debug, exports.title + " runSyncExec - promise rejected:" + reason); + errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason); + + errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason); + }); + + }); + + + rsPort.on('data', function (data){ + + rsPortReceivedData = [...rsPortReceivedData, ...data]; + + if (rsPortReceivedData[0] != 85) { + rsPortReceivedData = []; + return; + } + + let l = rsPortReceivedData.length; + + if (l < 4 ) return; + + if (l > 4 ) { + + // if array length is greater than 4, we take first 4 byte and do the logic, second 4 bytes, do the logic and so on + let i, j, temparray, chunk = 4; + for ( i = 0, j = l; i < j; i += chunk ) { + temparray = rsPortReceivedData.slice(i, i + chunk); + + if ( temparray.length < 4 ){ + rsPortReceivedData = [...temparray]; + return; + } + + switchLogic(temparray); + } + + rsPortReceivedData = []; + return; + } + + switchLogic(rsPortReceivedData); + + rsPortReceivedData = []; + + }); + + rsPort.on("close", () => { + rsPort.close(); + }) + + rsPort.open(); + + } + + + function handleWebSocket() { + + //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() { + + instance.send(0, exports.title + " running"); + turnOffAlarm(); + + // useTurnOffCounter = true; + // turnOffCounter = relaysData.length - 1; + initialSetting(); + ws.send(JSON.stringify({"cmd":"all"})); + + // 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 +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_07', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_08', +// debounce: 50, +// counter: 0, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, + ws.onmessage = function(data) { + + data = JSON.parse(data.data); + + // data comes in array except of "temperature" ==> it comes as an object + if(!Array.isArray(data)) + { + let value = data['value']; + + // temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB + if(Math.abs(previousValues["temperature"] - value) > 0.21 ) + { + const dataToTb = { + [FLOW.OMS_rvo_tbname]: [ + { + "ts": Date.now(), + "values": {temperature: value} + } + ] + }; + + deviceStatuses["temperature"] = "OK"; + previousValues["temperature"] = value; + instance.send(instanceSendTo.tb, dataToTb); + } + return; + } + + data.map(item => { + + let value = item['value']; + let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01" + + if (pin == undefined) return; + switchLogic(pin, value); + }) + } + + + ws.on('error', (err) => { + instance.send(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..."); + setTimeout(handleWebSocket, 1000); + } + } + + // ! do we need requests every minute ??? + // const startRequests = () => { + // console.log("startRequest function called"); + // start = setInterval(() => { + // // console.log("data from evok requested"); + // ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"})); + // // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]})); + // }, 150000) + // } + + + instance.on("close", () => { + if(rsPort) rsPort.close(); + if(ws) ws.close(); + clearInterval(sendRebuildTasksAt11); + }) + + loadAllDb(); + + function getPin(line) + { + //conversionTable + let keys = Object.keys(pinsData); + for(let i = 0; i < keys.length; i++) + { + let key = keys[i]; + + if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line) + { + if(rsPort) return key - 1; + if(ws) return key; + } + } + + logger.debug("no pin detected"); + + return null; + } + + + function turnOnAlarm() + { + if(FLOW.OMS_maintenance_mode) return; + + alarmStatus = "ON"; + + if(rsPort) + { + let arr = [0x55]; + arr.push( 13 ); + arr.push( 0 ); + arr.push( 1 ); + + rsPort.write(Buffer.from(arr), function(err) { + logger.debug("sirena zapnuta"); + }); + } + else if(ws) + { + let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1}; + ws.send(JSON.stringify(cmd)); + logger.debug("sirena zapnuta"); + } + } + + + function turnOffAlarm() + { + alarmStatus = "OFF"; + + if(rsPort) + { + let arr = [0x55]; + arr.push( 13 ); + arr.push( 0 ); + arr.push( 0 ); + + rsPort.write(Buffer.from(arr), function(err) { + logger.debug("sirena vypnuta"); + }); + } + else if(ws) + { + let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0}; + ws.send(JSON.stringify(cmd)); + logger.debug("sirena vypnuta"); + } + } + + + function reportLineStatus(line) + { + //Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false). + + let tbname = relaysData[line].tbname; + + let bits = []; + + if(deviceStatuses["state_of_breaker"][line] == "On") + { + bits.push(0); + } + else bits.push(1); + + if(deviceStatuses["state_of_contactor"][line] == "On") + { + bits.push(0); + } + else bits.push(1); + + resizeArray(bits, 8, 0); + + let byte = bitwise.byte.write(bits.reverse()); + + //console.log("line", line, bits, byte); + + let values = { + statecode: byte + } + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + //console.log(values); + + instance.send(instanceSendTo.tb, dataToTb); + } + + + function turnOnLine(line, pin, force, info) + { + + instance.send(instanceSendTo.debug, "turn on line " + line ); + if(force == undefined) force = false; + + if(line == 0) + { + if(alarmStatus == "ON") turnOffAlarm(); + FLOW.OMS_maintenance_mode = true; + + let values = {}; + values["statecode"] = calculateStateCode(); + values["power_mode"] = "maintenance"; + let tbname = relaysData[line].tbname; + sendTelemetry(values, tbname); + + monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info); + + return; + } + + if( pin === undefined) pin = getPin(line); + + monitor.info("turnOnLine (line, pin, force)", line, pin, force, info); + + if( pin === undefined) + { + monitor.info("pin is undefined!", line); + return; + } + + + if(!force) + { + if(relaysData[line].contactor == 1) + { + instance.send(instanceSendTo.debug, "line is already on " + line ); + logger.debug("turnOnLine: line is already on: ", line); + + return; + } + } + + // if(!rsPort.isOpen && !ws) + if(!rsPort && !ws) + { + errLogger.error("di do controller - port or websocket is not opened"); + return; + } + + if(rsPort) + { + let arr = [0x55]; + arr.push( pin ); + arr.push( 0 ); + arr.push( 1 ); + + rsPort.write(Buffer.from(arr), function(err) { + if(err === undefined) + { + console.log("turnONLine zapisal do rsPortu", line, arr); + switchLogic(arr); + } + else + { + monitor.info("turnOnLine WRITE error", err); + } + + }); + + } + else if(ws) + { + console.log("turnONLine pin (relay)", pin); + //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method + let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1}; + ws.send(JSON.stringify(cmd)); + //switchLogic(pin, 1) + } + } + + + function turnOffLine(line, pin, force, info) + { + if(force == undefined) force = false; + + if(line == 0) + { + FLOW.OMS_maintenance_mode = false; + + let values = {}; + values["statecode"] = calculateStateCode(); + values["power_mode"] = "automatic"; + let tbname = relaysData[line].tbname; + sendTelemetry(values, tbname); + + return; + } + + if( pin === undefined) pin = getPin(line); + + monitor.info("turnOffLine (line, pin, force)", line, pin, force, info); + + if( pin === undefined) + { + errLogger.error("pin is undefined!", line); + return; + } + + if(!force) + { + if(relaysData[line].contactor == 0) + { + instance.send(instanceSendTo.debug, "line is already off " + line ); + logger.debug("turnOffLine: line already off:", line); + + return; + } + } + + // if(!rsPort.isOpen && !ws) + if(!rsPort && !ws) + { + errLogger.error("di do controller - port or websocket is not opened"); + return; + } + + if(rsPort) + { + let arr = [0x55]; + arr.push( pin ); + arr.push( 0 ); + arr.push( 0 ); + + rsPort.write(Buffer.from(arr), function(err) { + if(err === undefined) + { + console.log("turnOffLine zapisal do rsPort-u", line, arr); + switchLogic(arr); + } + else + { + monitor.info("turnOffLine WRITE error", err); + } + + }); + + } + else if(ws) + { + //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method + //monitor.info("turnOffLine pin (relay)", pin); + let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0}; + ws.send(JSON.stringify(cmd)); + //switchLogic(pin, 0) + } + + } + + + //data from modbus_reader or temperature sensor or twilight sensor or other modbus device + instance.on("0", flowdata => { + + if(!flowdata.data instanceof Object) return; + + // console.log('***********************', flowdata.data) + instance.send(instanceSendTo.debug, flowdata.data); + + // we handle nok status from modbus_reader component and thermometer + if(flowdata.data?.status) + { + const status = flowdata.data.status; + if(status == "NOK-twilight_sensor") + { + deviceStatuses["twilight_sensor"] = "NOK"; + } + else if(status == "NOK-em340" || status == "NOK-em111") + { + deviceStatuses["em"] = "NOK"; + } + else if(status == "NOK-thermometer") + { + deviceStatuses["temperature"] = "NOK"; + } + 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(obj)){ + + rsPort.write(Buffer.from(obj), function(err) { + switchLogic(obj); + + instance.send(instanceSendTo.debug, {"WRITE":obj} ); + }); + } + }) + + + function calculateStateCode() + { + + let bytes = []; + let bits = []; + + //Hlavný istič - state_of_main_switch + if(deviceStatuses["state_of_main_switch"] == "On") + { + bits.push(0); + } + else if(deviceStatuses["state_of_main_switch"] == "Off") + { + bits.push(1); + } + + //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY + if(!FLOW.OMS_maintenance_mode) + { + if(deviceStatuses["rotary_switch_state"] == "Manual") + { + bits.push(0); + bits.push(1); + } + + if(deviceStatuses["rotary_switch_state"] == "Automatic") + { + bits.push(0); + bits.push(0); + } + + if(deviceStatuses["rotary_switch_state"] == "Off") + { + bits.push(1); + bits.push(0); + } + } + else{ + bits.push(1); + bits.push(1); + } + + //Dverový kontakt + if(deviceStatuses["door_condition"] == "closed") + { + bits.push(0); + } + else + { + bits.push(1); + } + + //EM + if(deviceStatuses["em"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + //Teplomer + if(deviceStatuses["temperature"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + //Batéria + if(deviceStatuses["battery"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + //Zdroj + if(deviceStatuses["power_supply"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + //MN + if(deviceStatuses["master_node"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + //výpadok napätia na fáze + if(deviceStatuses["no_voltage"] == "NOK") + { + bits.push(1); + } + else + { + bits.push(0); + } + + 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); + + return byte; + } + + + function checkFinalRVOStatus() { + + // we check if any of these pins values are 0 --> it means status RVO is "NOK" + // pinIndex 6 is door_condition - if open in maintenance mode - status = OK + + //set RVO state + + let status = "OK"; + + if(deviceStatuses["em"] == "NOK") + { + 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"; + } + + //ak teplomer NOK, rvo nok + if(deviceStatuses["temperature"] == "NOK") + { + + let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK"); + if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK"); + + status = "NOK"; + } + + if(status == "OK") + { + let pinIndexes = [1, 4, 6]; + if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05']; + + //console.log('-------- previousValues', previousValues); + + for (const pinIndex of pinIndexes) { + if (previousValues[pinIndex] === 0) { + + if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue; + + let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0"); + if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type); + + status = "NOK"; + + break; + } + } + } + + // battery status. If value is 1 - battery is NOK + if (previousValues[5] === 1) + { + let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery"); + if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery"); + + status = "NOK"; + } + + //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding); + + if(!FLOW.OMS_masterNodeIsResponding) + { + //errLogger.error("Master node is not responding"); + errorHandler.sendMessageToService("Master node is not responding"); + status = "NOK"; + + deviceStatuses["master_node"] = "NOK"; + } + else deviceStatuses["master_node"] = "OK"; + + //console.log("checkFinalRVOStatus", status); + if(FLOW.OMS_no_voltage.size > 0) + { + let writeToFile = errorHandler.processMessage("no voltage detected"); + if(writeToFile) errLogger.error("no voltage detected", FLOW.OMS_no_voltage); + + status = "NOK"; + + deviceStatuses["no_voltage"] = "NOK"; + } + else deviceStatuses["no_voltage"] = "OK"; + + if(status == "NOK") + { + sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname); + + return false; + } + + return true; + } + + + // 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, twilight; + + //data from rsPort + if(args.length == 1) + { + pinIndex = args[0][1] + 1; + if (pinIndex === 17) pinIndex--; + newPinValue = args[0][3]; + twilight = args[0][2]; + } + //data from websocket + else + { + pinIndex = args[0]; + newPinValue = args[1]; + } + + let obj = pinsData[pinIndex]; + + if(obj == undefined) + { + previousValues[pinIndex] = newPinValue; + return; + } + + let type = obj.type; + let line = obj.line; + let tbname = obj.tbname; + + //default value + let value = "On"; + if(newPinValue === 0) value = "Off"; + + //Hlavný istič + //! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri + //! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition' + if(type === "!!!state_of_main_switch") + { + if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) + { + sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); + values["status"] = "NOK"; + + deviceStatuses["state_of_main_switch"] = "Off"; + } + else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) + { + sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); + + deviceStatuses["state_of_main_switch"] = "On"; + } + } + + //Prevádzkový mód + if(type == "rotary_switch_state") + { + // combination of these two pins required to get result + let pin2, pin3; + if(pinIndex == 2 || pinIndex == "input1_02") + { + pin2 = newPinValue; + pin3 = previousValues[3] || previousValues["input1_03"]; + + if(pin3 == undefined) + { + previousValues[pinIndex] = newPinValue; + return; + } + } + else if(pinIndex == 3 || pinIndex == "input1_03") + { + pin3 = newPinValue; + pin2 = previousValues[2] || previousValues["input1_02"]; + + if(pin2 == undefined) + { + previousValues[pinIndex] = newPinValue; + return; + } + } + + //console.log('***********************', pin2, pin3) + if (pin2 == 1 && pin3 == 0) value = "Manual"; + if (pin2 == 0 && pin3 == 0) value = "Off"; + if (pin2 == 0 && pin3 == 1) value = "Automatic"; + + deviceStatuses["rotary_switch_state"] = value; + + //automatic - profilu pre nody sa vykonavaju + //ak je spracovany, a automatic - tak ho zapnem + //ak nie je spracovany, iba profil zapisem + + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value}); + + //console.log("rotary_switch_state pin", pin2, pin3, value); + } + //Zdroj - pin 4 + else if (type === "power_supply") + { + if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", instanceSendTo.tb, instance); + sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", instanceSendTo.tb, instance, "power_supply"); + values["status"] = "NOK"; + + deviceStatuses["power_supply"] = "NOK"; + } + else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", instanceSendTo.tb, instance); + sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", instanceSendTo.tb, instance, "power_supply"); + + deviceStatuses["power_supply"] = "OK"; + } + } + //Batéria - pin 5 + else if (type === "battery") + { + if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", instanceSendTo.tb, instance); + sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", instanceSendTo.tb, instance, "battery_level"); + values["status"] = "NOK"; + + deviceStatuses["battery"] = "NOK"; + } + else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", instanceSendTo.tb, instance); + sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", instanceSendTo.tb, instance, "battery_level"); + + deviceStatuses["battery"] = "OK"; + } + } + //Dverový kontakt - pin 6 + //! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch" + //! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition' + else if(type == "door_condition" || type === "state_of_main_switch") + { + newPinValue === 0 ? value = "open" : value = "closed"; + + if (newPinValue != previousValues[pinIndex]) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", instanceSendTo.tb, instance, "rvo_door"); + //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", instanceSendTo.tb, instance, "rvo_door"); + } + + if (value === "open" && FLOW.OMS_maintenance_mode) + { + sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", instanceSendTo.tb, instance, "rvo_door"); + } + + if (value === "open" && !FLOW.OMS_maintenance_mode) + { + //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", instanceSendTo.tb, instance); + sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", instanceSendTo.tb, instance, "rvo_door"); + values["status"] = "NOK"; + + //console.log(door_has_been_open_without_permision_alarm_is_on); + + // 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") + { + if(alarmStatus == "ON") turnOffAlarm(); + //turnOffAlarm(); + + sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", instanceSendTo.tb, instance, "rvo_door"); + } + + deviceStatuses["door_condition"] = value; + + } + //lux sensor + else if(type == "twilight_sensor") + { + //! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000. + //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 ); + + 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; + + //modify table relays + dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) { + + builder.callback(function(err, response) { + + /* + if(useTurnOffCounter) + { + turnOffCounter--; + + if(turnOffCounter <= 0) + { + useTurnOffCounter = false; + } + } + */ + + if(err == undefined) + { + + let time = 0; + if(value) time = 1000 * 10;//10 sekund + + let dataChanged = false; + if(relaysData[line].contactor != value) dataChanged = true; + relaysData[line].contactor = value; + + //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles + //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor + + setTimeout(function(){ + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); + }, time); + + reportLineStatus(line); + + + } + else + { + errLogger.error("modify table relays failed", err); + } + + + }); + }); + } + + if(type === "state_of_breaker") + { + + let valueChanged = false; + if(newPinValue != previousValues[pinIndex]) valueChanged = true; + + if(valueChanged) + { + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line}); + + //mame iba 3 istice. vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia (napr linia 1, paralelna s nou je linia 4, key je string "4") + // ak je 7 linii, na 1 istici je linia 1,4,7 + + if(line == 1) + { + + const lineOnSameBraker = [4,7]; + + for (var i = 0; i < lineOnSameBraker.length; i++) + { + if(!relaysData.hasOwnProperty(lineOnSameBraker[i])) continue; + + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i]}); + + deviceStatuses["state_of_breaker"][lineOnSameBraker[i]] = value; + reportLineStatus(lineOnSameBraker[i]); + + values[type] = value; + const tbname = relaysData[lineOnSameBraker[i]].tbname; + sendTelemetry(values, tbname); + + delete values[type]; + } + + } + else + { + const lineOnSameBraker = line + 3 + ""; + + if(relaysData.hasOwnProperty(lineOnSameBraker)) + { + instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3}); + + deviceStatuses["state_of_breaker"][line + 3] = value; + reportLineStatus(line + 3); + + values[type] = value; + const tbname = relaysData[lineOnSameBraker].tbname; + sendTelemetry(values, tbname); + + delete values[type]; + } + + } + + } + + if(value == "Off") values["status"] = "NOK"; + + deviceStatuses["state_of_breaker"][line] = value; + + reportLineStatus(line); + } + + values[type] = value; + + //if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode(); + + if(pinsData.hasOwnProperty(pinIndex)) + { + let valueChanged = false; + if(newPinValue != previousValues[pinIndex]) + { + valueChanged = true; + //pin was changed + previousValues[pinIndex] = newPinValue; + } + + let result = checkFinalRVOStatus(); + if(!result && line == 0) + { + values["status"] = "NOK"; + } + + if(type == "state_of_contactor") valueChanged = true; + if(type == "rotary_switch_state") valueChanged = true; + if(type === "state_of_breaker") + { + //console.log(type, values, valueChanged); + } + + if(FLOW.OMS_rvo_tbname == "") + { + console.log("FLOW.OMS_rvo_tbname is EMPTY"); + } + + if(FLOW.OMS_rvo_tbname == tbname) + { + values["statecode"] = calculateStateCode(); + //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname); + } + + if(valueChanged) + { + sendTelemetry(values, tbname); + } + + if(type == "rotary_switch_state") + { + if(FLOW.OMS_maintenance_mode) value = "maintenance"; + value = value.toLowerCase(); + + let values = {}; + values["power_mode"] = value; + + sendTelemetry(values, tbname); + } + } + else + { + logger.debug("no pinIndex", pinsData[pinIndex], pinsData); + } + + } + + + function sendTelemetry(values, tbname) + { + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] + } + + instance.send(instanceSendTo.tb, dataToTb); + } + +} + + + + +//! incomming data to websocket +// [ +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_08', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_01', +// alias: 'al_lights_kitchen', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_02', +// alias: 'al_lights_bedroom', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_03', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_04', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_05', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_06', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// glob_dev_id: 1, +// modes: [ 'Simple' ], +// value: 0, +// circuit: '1_07', +// pending: false, +// relay_type: 'physical', +// dev: 'relay', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_08', +// debounce: 50, +// counter: 0, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_mode: 'Enabled', +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// dev: 'input', +// modes: [ 'Simple', 'DirectSwitch' ], +// debounce: 50, +// counter: 1, +// value: 1, +// alias: 'al_main_switch', +// mode: 'Simple', +// circuit: '1_01' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 1, +// circuit: '1_02', +// debounce: 50, +// counter: 2, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 1, +// circuit: '1_03', +// debounce: 50, +// counter: 2, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_04', +// debounce: 50, +// counter: 1, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_05', +// debounce: 50, +// counter: 0, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_06', +// debounce: 50, +// counter: 0, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// counter_modes: [ 'Enabled', 'Disabled' ], +// glob_dev_id: 1, +// modes: [ 'Simple', 'DirectSwitch' ], +// value: 0, +// circuit: '1_07', +// debounce: 50, +// counter: 0, +// counter_mode: 'Enabled', +// dev: 'input', +// mode: 'Simple' +// }, +// { +// interval: 3, +// value: 24.5, +// circuit: '28744F7791180257', +// address: '28744F7791180257', +// time: 1631873896.48797, +// typ: 'DS18B20', +// lost: false, +// dev: 'temp' +// }, +// { +// bus: '/dev/i2c-2', +// interval: 3, +// dev: 'owbus', +// scan_interval: 300, +// circuit: '1', +// do_scan: false, +// do_reset: false +// }, +// { +// glob_dev_id: 1, +// last_comm: 0.014672994613647461, +// ver2: '0.1', +// sn: 42, +// circuit: '1', +// model: 'S207', +// dev: 'neuron', +// board_count: 1 +// }, +// { +// circuit: '1_01', +// value: 0, +// glob_dev_id: 1, +// dev: 'wd', +// timeout: 5000, +// was_wd_reset: 0, +// nv_save: 0 +// } +// ] + +//! loaded pins_data --> from LM +// { +// '1': { pin: 1, type: 'state_of_main_switch', line: 0 }, +// '2': { pin: 2, type: 'rotary_switch_state', line: 0 }, +// '3': { pin: 3, type: 'rotary_switch_state', line: 0 }, +// '4': { pin: 4, type: 'power_supply', line: 0 }, +// '5': { pin: 5, type: 'battery', line: 0 }, +// '6': { pin: 6, type: 'door_condition', line: 0 }, +// '8': { pin: 8, type: 'state_of_breaker', line: 1 }, +// '9': { pin: 9, type: 'state_of_breaker', line: 2 }, +// '10': { pin: 10, type: 'state_of_breaker', line: 3 }, +// '11': { pin: 11, type: 'state_of_contactor', line: 1 }, +// '12': { pin: 12, type: 'state_of_contactor', line: 2 }, +// '13': { pin: 13, type: 'state_of_contactor', line: 3 }, +// '16': { pin: 16, type: 'twilight_sensor', line: 0 } +// } + +//! pins.table --> from LM +// pin:number|type:string|line:number +// *|1|state_of_main_switch|0|........... +// *|2|rotary_switch_state|0|........... +// *|3|rotary_switch_state|0|........... +// *|4|power_supply|0|........... +// *|5|battery|0|........... +// *|6|door_condition|0|........... +// *|8|state_of_breaker|1|........... +// *|9|state_of_breaker|2|........... +// *|10|state_of_breaker|3|........... +// *|11|state_of_contactor|1|........... +// *|12|state_of_contactor|2|........... +// *|13|state_of_contactor|3|........... +// *|16|twilight_sensor|0|........... + +//! pins.table --> from UNIPI +// pin:string|type:string|line:number +// *|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 +// { +// '16': { pin: '16', type: 'twilight_sensor', line: 0 }, +// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 }, +// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 }, +// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 }, +// al_power: { pin: 'al_power', type: 'power_supply', line: 0 }, +// al_battery: { pin: 'al_battery', type: 'battery', line: 0 }, +// al_door: { pin: 'al_door', type: 'door_condition', line: 0 }, +// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 }, +// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 }, +// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 }, +// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 }, +// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 }, +// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 }, +// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 }, +// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 }, +// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', line: 0 } +// } + + +//! relays_data +// { +// '0': { +// line: 0, +// tbname: 'KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV', +// contactor: 1, +// profile: '' +// }, +// '1': { +// line: 1, +// tbname: 'RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O', +// contactor: 0, +// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' +// }, +// '2': { +// line: 2, +// tbname: 'dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7', +// contactor: 0, +// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' +// }, +// '3': { +// line: 3, +// tbname: 'vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V', +// contactor: 0, +// profile: '{"intervals":[{"value":0,"end_time":"20:30","start_time":"13:00"},{"value":1,"end_time":"00:10","start_time":"20:30"},{"value":0,"end_time":"13:00","start_time":"05:40"},{"value":1,"end_time":"05:40","start_time":"00:10"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' +// } +// } + + + + + +// { +// "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": "" +// } +// } +// } +// ] +// } diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js index d21839d..fd1ac62 100644 --- a/flow/modbus_reader.js +++ b/flow/modbus_reader.js @@ -3,7 +3,7 @@ exports.title = 'Modbus reader'; exports.version = '2.0.0'; exports.group = 'Worksys'; exports.color = '#2134B0'; -exports.output = ["red", "white"]; +exports.output = ["red", "white", "yellow"]; exports.click = false; exports.author = 'Rastislav Kovac'; exports.icon = 'bolt'; @@ -24,16 +24,18 @@ const errorHandler = new ErrorToServiceHandler(); const { sendNotification } = require('./helper/notification_reporter'); +const DELAY_BETWEEN_DEVICES = 10000; + const instanceSendTo = { debug: 0, dido_controller: 1, + tb: 2 }; //to handle NOK and OK sendNotifications s const numberOfNotResponding = {}; let tbName = null; - exports.install = function(instance) { class SocketWithClients { @@ -86,7 +88,7 @@ exports.install = function(instance) { this.socket.on('open', function () { console.log("socket connected"); obj.getActualStreamAndDevice(); - obj.timeoutInterval = timeoutInterval; + obj.timeoutInterval = timeoutInterval - DELAY_BETWEEN_DEVICES; // to make sure readout always runs in timeoutinterval we substract DELAY_BETWEEN_DEVICES }) }; @@ -101,7 +103,7 @@ exports.install = function(instance) { this.device = dev.device; //em340, twilight_sensor if(this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval); - else setTimeout(this.readRegisters, 2000); + else setTimeout(this.readRegisters, DELAY_BETWEEN_DEVICES); } readRegisters = () => { @@ -139,9 +141,7 @@ exports.install = function(instance) { obj.error = 0; obj.index++; - - if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0); - else obj.setNewStream(); + obj.readAnotherRegister(); }).catch (function () { @@ -177,12 +177,16 @@ exports.install = function(instance) { })) obj.index++; - if(obj.index < obj.lengthOfActualDeviceStream) setTimeout(obj.readRegisters, 0); - else obj.setNewStream(); + obj.readAnotherRegister(); }) }; + readAnotherRegister = () => { + if(this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0); + else this.setNewStream(); + } + transformResponse = (response, register, deviceAddress) => { for (let i = 0; i < this.lengthOfActualDeviceStream; i++) { From 31fe341ef166a1dfb17b602c0c5901c37bc99c62 Mon Sep 17 00:00:00 2001 From: rasta5man Date: Tue, 14 May 2024 16:17:58 +0200 Subject: [PATCH 4/9] refactoring - no change --- flow/cmd_manager.js | 2 +- flow/designer.json | 694 +++++++++++++++++++++----------------------- 2 files changed, 327 insertions(+), 369 deletions(-) diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 7f77d20..3c18f1d 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -2261,7 +2261,7 @@ exports.install = function(instance) { //if(state_of_breaker[line] == "Off") disconnected = true; } - //toto sa reportuje po prijati dat z di_do_controlera + //toto sa reportuje po prijati dat z dido_controlera if(disconnected) { diff --git a/flow/designer.json b/flow/designer.json index 9fe9d06..7cb3ebb 100644 --- a/flow/designer.json +++ b/flow/designer.json @@ -20,37 +20,13 @@ } ], "components": [ - { - "id": "1611938192035", - "component": "debug", - "tab": "1611921777196", - "name": "modbus_ddebug", - "x": 400.5, - "y": 121.5, - "connections": {}, - "disabledio": { - "input": [], - "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": 404, - "y": 29, + "y": 36, "connections": {}, "disabledio": { "input": [], @@ -60,35 +36,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#DA4453", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#DA4453", - "notes": "" - }, - { - "id": "1612772119611", - "component": "virtualwireout", - "tab": "1611921777196", - "name": "tb-push", - "x": 399.75, - "y": 211.5, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "tb-push", - "color": "gray" - }, - "options": { - "wirename": "tb-push" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1612776786008", @@ -96,7 +50,7 @@ "tab": "1612772287426", "name": "WS MQTT publish", "x": 311.75, - "y": 268, + "y": 248, "connections": { "0": [ { @@ -133,14 +87,14 @@ "text": "Connected", "color": "green" }, + "color": "#888600", + "notes": "", "options": { "username": "", "clientid": "", "port": "1883", "host": "" - }, - "color": "#888600", - "notes": "" + } }, { "id": "1612778461252", @@ -148,7 +102,7 @@ "tab": "1612772287426", "name": "tb-push", "x": 68.75, - "y": 289, + "y": 269, "connections": { "0": [ { @@ -169,11 +123,11 @@ "text": "tb-push", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "tb-push" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1612783322136", @@ -181,7 +135,7 @@ "tab": "1612772287426", "name": "to TB", "x": 317.75, - "y": 174, + "y": 154, "connections": {}, "disabledio": { "input": [ @@ -193,33 +147,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "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": 32, - "connections": {}, - "disabledio": { - "input": [], - "output": [] - }, - "state": { - "text": "", - "color": "gray" - }, - "options": {}, - "color": "#704cff", - "notes": "" + } }, { "id": "1615551060773", @@ -227,7 +161,7 @@ "tab": "1612772287426", "name": "errors from MQTT Broker", "x": 610, - "y": 131, + "y": 111, "connections": {}, "disabledio": { "input": [ @@ -239,21 +173,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#DA4453", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#DA4453", - "notes": "" + } }, { "id": "1615563373927", "component": "debug", "tab": "1615551125555", "name": "Debug", - "x": 763, - "y": 123, + "x": 755, + "y": 19, "connections": {}, "disabledio": { "input": [ @@ -265,21 +199,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#DA4453", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#DA4453", - "notes": "" + } }, { "id": "1615566865233", "component": "virtualwireout", "tab": "1615551125555", "name": "tb-push", - "x": 761, - "y": 216, + "x": 753, + "y": 112, "connections": {}, "disabledio": { "input": [], @@ -289,19 +223,19 @@ "text": "tb-push", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "tb-push" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1615798582262", "component": "debug", "tab": "1615551125555", "name": "CMD_debug", - "x": 758, - "y": 301, + "x": 750, + "y": 197, "connections": {}, "disabledio": { "input": [ @@ -313,21 +247,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1615802995322", "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 398.8833312988281, - "y": 477.3500061035156, + "x": 400.8833312988281, + "y": 484.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -339,21 +273,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1615809128443", "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 406.8833312988281, - "y": 567.3500061035156, + "x": 405.8833312988281, + "y": 566.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -365,21 +299,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1615809595184", "component": "virtualwireout", "tab": "1611921777196", "name": "tb-push", - "x": 404.8833312988281, - "y": 653.25, + "x": 401.8833312988281, + "y": 306.25, "connections": {}, "disabledio": { "input": [], @@ -389,19 +323,19 @@ "text": "tb-push", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "tb-push" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1616165795916", "component": "httproute", "tab": "1615551125555", "name": "POST /terminal", - "x": 110, - "y": 508, + "x": 72, + "y": 350, "connections": { "0": [ { @@ -422,6 +356,9 @@ "text": "Listening", "color": "green" }, + "color": "#5D9CEC", + "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", + "cloning": false, "options": { "timeout": 10, "cachepolicy": 0, @@ -436,18 +373,15 @@ 10000 ], "emptyresponse": false - }, - "color": "#5D9CEC", - "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", - "cloning": false + } }, { "id": "1616165824813", "component": "httpresponse", "tab": "1615551125555", "name": "HTTP Response", - "x": 759, - "y": 377, + "x": 751, + "y": 273, "connections": {}, "disabledio": { "input": [], @@ -457,19 +391,19 @@ "text": "", "color": "gray" }, + "color": "#5D9CEC", + "notes": "", "options": { "datatype": "json" - }, - "color": "#5D9CEC", - "notes": "" + } }, { "id": "1617104731852", "component": "debug", "tab": "1615551125555", "name": "DIDO_Debug", - "x": 743, - "y": 839, + "x": 739, + "y": 635, "connections": {}, "disabledio": { "input": [ @@ -481,21 +415,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1617114651703", "component": "trigger", "tab": "1615551125555", "name": "turnOff line", - "x": 75, - "y": 1033, + "x": 71, + "y": 829, "connections": { "0": [ { @@ -512,20 +446,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "data": "{line: 3, command: \"turnOff\", force: true}", "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1617115013095", "component": "virtualwireout", "tab": "1615551125555", "name": "tb-push", - "x": 751, - "y": 940, + "x": 747, + "y": 736, "connections": {}, "disabledio": { "input": [], @@ -535,19 +469,19 @@ "text": "tb-push", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "tb-push" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1617178324650", "component": "debug", "tab": "1615551125555", "name": "Debug", - "x": 628, - "y": 1246, + "x": 605, + "y": 1024, "connections": {}, "disabledio": { "input": [], @@ -557,21 +491,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1617179044099", "component": "trigger", "tab": "1615551125555", "name": "start import", - "x": 258, - "y": 1254, + "x": 235, + "y": 1032, "connections": { "0": [ { @@ -588,20 +522,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "datatype": "object", "data": "{table: \"konsberg_production_line_operations_error\", startFrom: 1, delimiter: \";\", uniqueColumn: \"\", path: \"flow/operations_error.csv\", mapImport: {0: \"production_line\",\t1: \"operation\", 2: \"error_type\", 3: \"error_code\", 4: \"error_text\", 5: \"error_text_user_defined\"}}" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1617180390661", "component": "csv_import", "tab": "1615551125555", "name": "CsvImport", - "x": 437, - "y": 1235, + "x": 414, + "y": 1013, "connections": { "0": [ { @@ -618,19 +552,19 @@ "text": "", "color": "gray" }, + "color": "#2134B0", + "notes": "", "options": { "edge": "undefined" - }, - "color": "#2134B0", - "notes": "" + } }, { "id": "1617197763128", "component": "comment", "tab": "1615551125555", "name": "import data from csv", - "x": 424, - "y": 1168, + "x": 401, + "y": 946, "connections": {}, "disabledio": { "input": [], @@ -640,17 +574,17 @@ "text": "", "color": "gray" }, - "options": {}, "color": "#704cff", - "notes": "" + "notes": "", + "options": {} }, { "id": "1617284749681", "component": "trigger", "tab": "1615551125555", "name": "update profile / node", - "x": 119, - "y": 130, + "x": 80, + "y": 13, "connections": { "0": [ { @@ -667,20 +601,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "datatype": "string", "data": "profile_nodes" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1618235171399", "component": "trigger", "tab": "1615551125555", - "name": "run tasks", - "x": 122, - "y": 206, + "name": "tun tasks", + "x": 77, + "y": 84, "connections": { "0": [ { @@ -697,11 +631,11 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "data": "run" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1618300858252", @@ -709,7 +643,7 @@ "tab": "1612772287426", "name": "wsmqtt-exit1", "x": 610.8833312988281, - "y": 219, + "y": 199, "connections": {}, "disabledio": { "input": [], @@ -719,13 +653,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1618300863816", @@ -733,7 +667,7 @@ "tab": "1612772287426", "name": "wsmqtt-exit2", "x": 611.8833312988281, - "y": 394, + "y": 374, "connections": {}, "disabledio": { "input": [ @@ -745,21 +679,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1618393583970", "component": "virtualwireout", "tab": "1615551125555", "name": "to-cmd-manager", - "x": 744.8833312988281, - "y": 1032, + "x": 740.8833312988281, + "y": 828, "connections": {}, "disabledio": { "input": [], @@ -769,19 +703,19 @@ "text": "from-dido-controller", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "from-dido-controller" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1618393674428", "component": "virtualwirein", "tab": "1615551125555", "name": "platform-rpc-call", - "x": 115.88333129882812, - "y": 316, + "x": 77.88333129882812, + "y": 173, "connections": { "0": [ { @@ -798,19 +732,19 @@ "text": "platform-rpc-call", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "platform-rpc-call" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1618393759854", "component": "virtualwirein", "tab": "1615551125555", "name": "cmd_to_dido", - "x": 78.88333129882812, - "y": 864, + "x": 76.88333129882812, + "y": 678, "connections": { "0": [ { @@ -831,19 +765,19 @@ "text": "cmd_to_dido", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "cmd_to_dido" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1618393827655", "component": "virtualwireout", "tab": "1615551125555", "name": "cmd_to_dido", - "x": 756.8833312988281, - "y": 477, + "x": 748.8833312988281, + "y": 373, "connections": {}, "disabledio": { "input": [], @@ -853,11 +787,11 @@ "text": "cmd_to_dido", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "cmd_to_dido" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1618558465485", @@ -865,7 +799,7 @@ "tab": "1612772287426", "name": "platform-rpc-call", "x": 611.8833312988281, - "y": 307, + "y": 287, "connections": {}, "disabledio": { "input": [], @@ -875,19 +809,19 @@ "text": "platform-rpc-call", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "platform-rpc-call" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1618572059773", "component": "trigger", "tab": "1615551125555", "name": "turnOn line", - "x": 76, - "y": 947, + "x": 72, + "y": 756, "connections": { "0": [ { @@ -904,20 +838,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "datatype": "object", "data": "{line: 1, command: \"turnOn\", force: true}" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1619515097737", "component": "cmd_manager", "tab": "1615551125555", "name": "CMD Manager", - "x": 442, - "y": 290, + "x": 420, + "y": 156, "connections": { "0": [ { @@ -962,17 +896,17 @@ "text": "", "color": "gray" }, - "options": {}, "color": "#5D9CEC", - "notes": "" + "notes": "", + "options": {} }, { "id": "1619605019281", "component": "httproute", "tab": "1615551125555", "name": "GET db", - "x": 104, - "y": 619, + "x": 73, + "y": 455, "connections": { "0": [ { @@ -993,6 +927,9 @@ "text": "Listening", "color": "green" }, + "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, "options": { "timeout": 5, "cachepolicy": 0, @@ -1006,18 +943,15 @@ "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": 72, - "y": 1106, + "x": 68, + "y": 902, "connections": { "0": [ { @@ -1034,20 +968,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "data": "{command: \"turnOnAlarm\"}", "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1619784812964", "component": "trigger", "tab": "1615551125555", "name": "turnOffAlarm", - "x": 71, - "y": 1179, + "x": 67, + "y": 975, "connections": { "0": [ { @@ -1064,20 +998,20 @@ "text": "", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "data": "{command: \"turnOffAlarm\"}", "datatype": "object" - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1621340721628", "component": "virtualwireout", "tab": "1611921777196", "name": "modbus_to_dido", - "x": 396, - "y": 390, + "x": 403, + "y": 394, "connections": {}, "disabledio": { "input": [], @@ -1087,11 +1021,11 @@ "text": "modbus_to_dido", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "modbus_to_dido" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1622640022885", @@ -1116,6 +1050,9 @@ "text": "Listening", "color": "green" }, + "color": "#5D9CEC", + "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, "options": { "timeout": 5, "cachepolicy": 0, @@ -1128,10 +1065,7 @@ "post", 5000 ] - }, - "color": "#5D9CEC", - "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 + } }, { "id": "1622640073521", @@ -1156,11 +1090,11 @@ "text": "", "color": "gray" }, + "color": "#2134B0", + "notes": "", "options": { "edge": "undefined" - }, - "color": "#2134B0", - "notes": "" + } }, { "id": "1622641420685", @@ -1178,9 +1112,9 @@ "text": "", "color": "gray" }, - "options": {}, "color": "#5D9CEC", - "notes": "" + "notes": "", + "options": {} }, { "id": "1634303504177", @@ -1188,7 +1122,7 @@ "tab": "1612772287426", "name": "RAM", "x": 71.88333129882812, - "y": 629.5, + "y": 609.5, "connections": { "0": [ { @@ -1202,15 +1136,15 @@ "output": [] }, "state": { - "text": "826.22 MB / 985.68 MB", + "text": "801.23 MB / 987.80 MB", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "enabled": true, "interval": 30000 - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1634303533779", @@ -1218,7 +1152,7 @@ "tab": "1612772287426", "name": "disk", "x": 72.88333129882812, - "y": 726.5, + "y": 706.5, "connections": { "0": [ { @@ -1232,16 +1166,16 @@ "output": [] }, "state": { - "text": "5.85 GB / 7.26 GB", + "text": "5.90 GB / 7.26 GB", "color": "gray" }, + "color": "#F6BB42", + "notes": "", "options": { "enabled": true, "path": "/", "interval": 30000 - }, - "color": "#F6BB42", - "notes": "" + } }, { "id": "1634303595494", @@ -1249,7 +1183,7 @@ "tab": "1612772287426", "name": "send-to-services", "x": 5.883331298828125, - "y": 1089.5, + "y": 1069.5, "connections": { "0": [ { @@ -1270,11 +1204,11 @@ "text": "send-to-services", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "send-to-services" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1634303602169", @@ -1282,7 +1216,7 @@ "tab": "1612772287426", "name": "send-to-services", "x": 428.8833312988281, - "y": 622.5, + "y": 602.5, "connections": {}, "disabledio": { "input": [], @@ -1292,11 +1226,11 @@ "text": "send-to-services", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "send-to-services" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1634303685503", @@ -1304,7 +1238,7 @@ "tab": "1612772287426", "name": "send-to-services", "x": 612.8833312988281, - "y": 482.5, + "y": 462.5, "connections": {}, "disabledio": { "input": [], @@ -1314,11 +1248,11 @@ "text": "send-to-services", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "send-to-services" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1634303743260", @@ -1327,7 +1261,7 @@ "name": "http://192.168.252.2:8004/sentmessage", "reference": "", "x": 439.8833312988281, - "y": 1096.7333374023438, + "y": 1076.7333374023438, "connections": { "0": [ { @@ -1344,13 +1278,13 @@ "text": "", "color": "gray" }, + "color": "#5D9CEC", + "notes": "", "options": { "stringify": "json", "method": "POST", "url": "http://192.168.252.2:8004/sentmessage" - }, - "color": "#5D9CEC", - "notes": "" + } }, { "id": "1634463186563", @@ -1358,7 +1292,7 @@ "tab": "1612772287426", "name": "Debug", "x": 234.75, - "y": 1044, + "y": 1024, "connections": {}, "disabledio": { "input": [ @@ -1370,13 +1304,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1634464580289", @@ -1384,7 +1318,7 @@ "tab": "1612772287426", "name": "Code", "x": 255, - "y": 532, + "y": 512, "connections": { "0": [ { @@ -1405,13 +1339,13 @@ "text": "", "color": "gray" }, + "color": "#656D78", + "notes": "", "options": { "keepmessage": true, "code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);", "outputs": 1 - }, - "color": "#656D78", - "notes": "" + } }, { "id": "1634465243324", @@ -1419,7 +1353,7 @@ "tab": "1612772287426", "name": "Debug", "x": 430, - "y": 528, + "y": 508, "connections": {}, "disabledio": { "input": [ @@ -1431,13 +1365,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1634465281992", @@ -1445,7 +1379,7 @@ "tab": "1612772287426", "name": "Code", "x": 244, - "y": 628, + "y": 608, "connections": { "0": [ { @@ -1466,13 +1400,13 @@ "text": "", "color": "gray" }, + "color": "#656D78", + "notes": "", "options": { "keepmessage": true, "code": "value.sender = \"ram\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.memory_total = (total).toFixed(0) + ' MB';\n//value.memory_free = (free).toFixed(0) + ' MB';\n//value.memory_used = (used).toFixed(0) + ' MB';\n\nresponse.memory_total = value.total;\nresponse.memory_free = value.free;\nresponse.memory_used = value.used;\n\nsend(0, response);", "outputs": 1 - }, - "color": "#656D78", - "notes": "" + } }, { "id": "1634465338103", @@ -1480,7 +1414,7 @@ "tab": "1612772287426", "name": "Debug", "x": 431, - "y": 720, + "y": 700, "connections": {}, "disabledio": { "input": [ @@ -1492,13 +1426,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1634465821120", @@ -1506,7 +1440,7 @@ "tab": "1612772287426", "name": "Code", "x": 247, - "y": 722, + "y": 702, "connections": { "0": [ { @@ -1527,13 +1461,13 @@ "text": "", "color": "gray" }, + "color": "#656D78", + "notes": "", "options": { "keepmessage": true, "code": "value.sender = \"hdd\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.hdd_total = (total).toFixed(0) + ' MB';\n//value.hdd_free = (free).toFixed(0) + ' MB';\n//value.used = (used).toFixed(0) + ' MB';\n\nresponse.hdd_total = value.total;\nresponse.hdd_free = value.free;\nresponse.hdd_used = value.used;\n\nsend(0, response);", "outputs": 1 - }, - "color": "#656D78", - "notes": "" + } }, { "id": "1634465892500", @@ -1541,7 +1475,7 @@ "tab": "1612772287426", "name": "Debug", "x": 434, - "y": 812, + "y": 792, "connections": {}, "disabledio": { "input": [ @@ -1553,13 +1487,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1634484067516", @@ -1567,7 +1501,7 @@ "tab": "1612772287426", "name": "Send info", "x": 438, - "y": 1205, + "y": 1185, "connections": {}, "disabledio": { "input": [ @@ -1579,13 +1513,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1634488120710", @@ -1593,7 +1527,7 @@ "tab": "1612772287426", "name": "Info sender", "x": 233, - "y": 1142, + "y": 1122, "connections": { "0": [ { @@ -1614,11 +1548,11 @@ "text": "", "color": "gray" }, + "color": "#2134B0", + "notes": "", "options": { "edge": "undefined" - }, - "color": "#2134B0", - "notes": "" + } }, { "id": "1635327431236", @@ -1626,7 +1560,7 @@ "tab": "1612772287426", "name": "Debug", "x": 811.8833312988281, - "y": 1090.5, + "y": 1070.5, "connections": {}, "disabledio": { "input": [ @@ -1638,21 +1572,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1635936391935", "component": "virtualwireout", "tab": "1615551125555", "name": "send-to-services", - "x": 756, - "y": 568, + "x": 748, + "y": 464, "connections": {}, "disabledio": { "input": [], @@ -1662,11 +1596,11 @@ "text": "send-to-services", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "send-to-services" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1637069803394", @@ -1674,7 +1608,7 @@ "tab": "1612772287426", "name": "CPU", "x": 71, - "y": 535, + "y": 515, "connections": { "0": [ { @@ -1688,9 +1622,11 @@ "output": [] }, "state": { - "text": "0.9% / 86.46 MB", + "text": "11.7% / 69.98 MB", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "monitorfiles": true, "monitorconnections": true, @@ -1698,17 +1634,15 @@ "monitorconsumption": true, "enabled": true, "interval": 30000 - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1683664161036", "component": "debug", "tab": "1615551125555", "name": "CMDtoDIDO", - "x": 417, - "y": 858, + "x": 413, + "y": 654, "connections": {}, "disabledio": { "input": [ @@ -1720,21 +1654,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1683981346282", "component": "virtualwirein", "tab": "1615551125555", "name": "from-dido-controller", - "x": 113, - "y": 423, + "x": 71, + "y": 260, "connections": { "0": [ { @@ -1755,19 +1689,19 @@ "text": "from-dido-controller", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "from-dido-controller" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1684055037116", "component": "debug", "tab": "1615551125555", "name": "from dido to cmd", - "x": 441, - "y": 461, + "x": 423, + "y": 331, "connections": {}, "disabledio": { "input": [ @@ -1779,21 +1713,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1684060205000", "component": "debug", "tab": "1615551125555", "name": "HTTP routes", - "x": 441, - "y": 564, + "x": 423, + "y": 422, "connections": {}, "disabledio": { "input": [ @@ -1805,21 +1739,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1684179110403", "component": "debug", "tab": "1611921777196", "name": "MDBToDido", - "x": 402, - "y": 300, + "x": 401, + "y": 125, "connections": {}, "disabledio": { "input": [], @@ -1829,21 +1763,21 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1699963668903", "component": "dido_controller", "tab": "1615551125555", "name": "DIDO_Controller", - "x": 406, - "y": 940, + "x": 402, + "y": 736, "connections": { "0": [ { @@ -1876,19 +1810,19 @@ "text": "", "color": "gray" }, + "color": "#2134B0", + "notes": "", "options": { "edge": "undefined" - }, - "color": "#2134B0", - "notes": "" + } }, { "id": "1699964678894", "component": "virtualwirein", "tab": "1615551125555", "name": "modbus_to_dido", - "x": 83, - "y": 775, + "x": 79, + "y": 595, "connections": { "0": [ { @@ -1909,19 +1843,19 @@ "text": "modbus_to_dido", "color": "gray" }, + "color": "#303E4D", + "notes": "", "options": { "wirename": "modbus_to_dido" - }, - "color": "#303E4D", - "notes": "" + } }, { "id": "1699964793925", "component": "debug", "tab": "1615551125555", "name": "modbusToDido", - "x": 415, - "y": 765, + "x": 411, + "y": 561, "connections": {}, "disabledio": { "input": [ @@ -1933,13 +1867,13 @@ "text": "Enabled", "color": "gray" }, + "color": "#967ADC", + "notes": "", "options": { "type": "data", "repository": false, "enabled": true - }, - "color": "#967ADC", - "notes": "" + } }, { "id": "1699965957410", @@ -1968,11 +1902,11 @@ "2": [ { "index": "0", - "id": "1621340721628" + "id": "1615809595184" }, { "index": "0", - "id": "1684179110403" + "id": "1714752862828" } ] }, @@ -1984,17 +1918,17 @@ "text": "", "color": "gray" }, - "options": {}, "color": "#2134B0", - "notes": "" + "notes": "", + "options": {} }, { "id": "1700411878636", "component": "thermometer", "tab": "1611921777196", "name": "Thermometer", - "x": 94.75, - "y": 414, + "x": 103.75, + "y": 408, "connections": { "0": [ { @@ -2027,10 +1961,34 @@ "text": "", "color": "gray" }, - "options": {}, "color": "#5CB36D", - "notes": "" + "notes": "", + "options": {} + }, + { + "id": "1714752862828", + "component": "debug", + "tab": "1611921777196", + "name": "MDBToTb", + "x": 402, + "y": 215, + "connections": {}, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "Enabled", + "color": "gray" + }, + "color": "#967ADC", + "notes": "", + "options": { + "type": "data", + "repository": false, + "enabled": true + } } ], - "version": 615 + "version": 618 } \ No newline at end of file From d289a99d07058bca3082ed3d149f9a078baaa12e Mon Sep 17 00:00:00 2001 From: rasta5man Date: Tue, 14 May 2024 16:29:11 +0200 Subject: [PATCH 5/9] new switching line functionality - in progress --- flow/cmd_manager.js | 2660 ++++++++++++++++++++++----------------- flow/dido_controller.js | 9 +- flow/modbus_reader.js | 10 +- 3 files changed, 1485 insertions(+), 1194 deletions(-) diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 3c18f1d..b3f9871 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -19,15 +19,15 @@ exports.html = `
RPC - run RPC calls

-
@(User)
-
-
-
@(Password)
-
-
-
@(My edge)
-
-
+
@(User)
+
+
+
@(Password)
+
+
+
@(My edge)
+
+
`; @@ -43,38 +43,49 @@ 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 { promisifyBuilder, makeMapFromDbResult} = require('./helper/db_helper.js'); const { sendNotification, initNotifications, ERRWEIGHT } = require('./helper/notification_reporter.js'); +const dbNodes = TABLE("nodes"); +const dbRelays = TABLE("relays"); +const dbSettings = TABLE("settings"); + //https://github.com/log4js-node/log4js-node/blob/master/examples/example.js //file: { type: 'file', filename: path.join(__dirname, 'log/file.log') } - var path = require('path'); var log4js = require("log4js"); const process = require('process'); -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' } - } -}); +//TODO - to remove? +// runTasks intervals +const SHORT_INTERVAL = 50; +const LONG_INTERVAL = 500; -const errLogger = log4js.getLogger("errLogs"); -const logger = log4js.getLogger(); -const monitor = log4js.getLogger("monitorLogs"); +//send data to following instances: +const SEND_TO = { + debug: 0, + tb: 1, + http_response: 2, + dido_controller: 3, + infoSender: 4 +} -//USAGE -//logger.debug("text") -//monitor.info('info'); -//errLogger.error("some error"); +const PRIORITY_TYPES = { + terminal: 0, + fw_detection: 1,//reserved only for FW detection - FLOW.OMS_masterNodeIsResponding + high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform) + relay_profile: 3, + node_broadcast: 4, + node_profile: 5, + node_cmd: 6 +} + +//list of command calls to process. Processing in runTasks function +let tasks = []; + +let interval = null;//timeout for procesing tasks +let refFlowdata = null;//holds reference to httprequest flowdata +let refFlowdataObj = {}; //load from settings let latitude = 48.70826502;//48.682255758; @@ -111,15 +122,9 @@ priorities["8"] = minutes; priorities["3"] = minutes; priorities["89"] = minutes; -//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app +//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming) let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89]; -//1 - dimming - -const dbNodes = TABLE("nodes"); -const dbRelays = TABLE("relays"); -const dbSettings = TABLE("settings"); - const errorHandler = new ErrorToServiceHandler(); let rotary_switch_state = "Off"; @@ -133,6 +138,35 @@ let nodesData = {};//key is node, value data from db //helper container for counting resolved group of commands (commands related to set profile) let cmdCounter = {};//key is node, value is counter let cmdNOKNodeCounter = {};//key is node, value is counter + +//END OF VARIABLE SETTINGS +//-------------------------------- + + +log4js.configure({ + appenders: { + errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') }, + monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') }, + console: { type: 'console' } + }, + categories: { + errLogs: { appenders: ['console', 'errLogs'], level: 'error' }, + monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' }, + //another: { appenders: ['console'], level: 'trace' }, + default: { appenders: ['console'], level: 'trace' } + } +}); + +const errLogger = log4js.getLogger("errLogs"); +const logger = log4js.getLogger(); +const monitor = log4js.getLogger("monitorLogs"); + +//USAGE +//logger.debug("text") +//monitor.info('info'); +//errLogger.error("some error"); + + function cmdCounterResolve(address) { if(cmdCounter.hasOwnProperty(address)) @@ -141,13 +175,12 @@ function cmdCounterResolve(address) let result = cmdCounter[address]; if(result == 0) delete cmdCounter[address]; - return result; } - return -1; } + function getParams(priority) { let params = {}; @@ -163,25 +196,25 @@ function getParams(priority) params.rw = 0;//0: read, 1: write //other values - //params.type = "cmd"; "relay" "cmd-terminal" + //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles" "edge_date_time" "number_of_luminaires" //params.tbname = tbname; - params.priority = priorityTypes.node_cmd;//default priority - params.timestamp = 0;//execution time + params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority + params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed if(priority != undefined ) { params.timestamp = priority; params.priority = priority; } - params.addMinutesToTimestamp = 0;//repeat if > 0, + params.addMinutesToTimestamp = 0;//repeat task if value is > 0, - //params.isDusk = false; - //params.isDawn = false; + //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint" //params.info = ""; return params; } + async function loadSettings() { let responseSettings = await promisifyBuilder(dbSettings.find()); @@ -200,12 +233,10 @@ async function loadSettings() //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) { @@ -246,13 +277,13 @@ function processNodeProfile(node) logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile); //return; - //let timestamp = priorityTypes.node_cmd; + //let timestamp = PRIORITY_TYPES.node_cmd; //let now = new Date(); //now.setSeconds(now.getSeconds() + 10); //let timestamp = now.getTime(); - let timestamp = priorityTypes.node_cmd; + let timestamp = PRIORITY_TYPES.node_cmd; //nodeProfile = undefined; removeTask({type: "set_node_profile", address: node}); @@ -270,7 +301,7 @@ function processNodeProfile(node) logger.debug("turn off profile"); - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.byte1 = 0; @@ -288,7 +319,7 @@ function processNodeProfile(node) tasks.push(params); - //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", instanceSendTo.tb, instance ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", SEND_TO.tb, instance ); } else { @@ -296,10 +327,10 @@ function processNodeProfile(node) //cmdCounter[node] = tasksProfile.length; //tasks.push(tasksProfile); - //let timestamp = priorityTypes.node_cmd; + //let timestamp = PRIORITY_TYPES.node_cmd; - //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu - let params = getParams(priorityTypes.node_cmd); + //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.byte1 = 0; @@ -335,7 +366,7 @@ function processNodeProfile(node) 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é + Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované Register úrovne má rovnaký formát ako dimming register (Reg 1). */ @@ -353,7 +384,7 @@ function processNodeProfile(node) logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node); - params = getParams(priorityTypes.node_cmd); + params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.byte1 = parseInt(t[0]);//hh @@ -372,7 +403,7 @@ function processNodeProfile(node) register++; timestamp++; - params = getParams(priorityTypes.node_cmd); + params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.byte1 = 0; @@ -407,7 +438,7 @@ function processNodeProfile(node) logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node); - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.register = 96; @@ -445,7 +476,7 @@ function processNodeProfile(node) logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node); - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.register = 97; @@ -482,12 +513,12 @@ function processNodeProfile(node) { //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) + //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); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.register = 98; @@ -527,7 +558,7 @@ function processNodeProfile(node) logger.debug("Time schedule settings - turn on", node); - params = getParams(priorityTypes.node_cmd); + params = getParams(PRIORITY_TYPES.node_cmd); params.type = "set_node_profile"; params.address = node; params.register = 8; @@ -556,7 +587,7 @@ function processNodeProfile(node) //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu) bits.push(0); - //Bity 6-7 - zatiaľ nepoužité + //Bity 6-7 - zatiaľ nepoužité bits.push(0); bits.push(0); @@ -607,53 +638,29 @@ function processNodeProfile(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(); + 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]; + //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 ]; - } - } + 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) => { @@ -665,25 +672,41 @@ function removeTask(obj) { 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) { + let now = new Date(); + console.log("CMD Manager installed", now.toLocaleString("sk-SK")); + + const tbHandler = new DataToTbHandler(SEND_TO.tb); + tbHandler.setSender(exports.title); + + //FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name + //const errorHandler = new ErrorToServiceHandler(instance, SEND_TO.infoSender); + errorHandler.setProjectsId(FLOW.OMS_projects_id); + //const errorHandler = new ErrorToServiceHandler(instance); + //errorHandler.sendMessageToService("ahoj", 0); + + let sunCalcResult = calculateDuskDawn(); + + let reportDuskDawn = { + dusk_time: sunCalcResult.dusk_time, + dawn_time: sunCalcResult.dawn_time, + dusk_time_reported: undefined, + dawn_time_reported: undefined + }; + + process.on('uncaughtException', function (err) { //TODO send to service @@ -697,253 +720,170 @@ exports.install = function(instance) { //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) + function processAllNodeProfilesOnLine(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); - - }) + + for (let k in nodesData) { + //node:number|tbname:string|line:number|profile:string|processed:boolean + + if(line == nodesData[k].line) + { + let node = nodesData[k].node; + let processed = nodesData[k].processed; + + if(!processed) + { + processNodeProfile(node); + } + else + { + logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`); + } + } + } } + + async function loadRelaysData(line) { + + relaysData = await promisifyBuilder(dbRelays.find()); + relaysData = makeMapFromDbResult(relaysData, "line"); + + for (const [key, value] of Object.entries(relaysData)) + { + if(key == "0") continue; + if(line != undefined) + { + //ak sa jedna o update profilu linie - pozor di_co_controller posiela command pre loadRelaysData + if(line != value.line ) continue; + } + + if(value.contactor == 1) processAllNodeProfilesOnLine(value.line); + } + +// console.log('.........', relaysData); + } + + function reportOnlineNodeStatus(line) { - //broadcast cas, o 1-2 sek neskor - status, brightness - + //broadcast cas, o 3 sek neskor - status, brightness //Po zapnutí línie broadcastovo aktualizovať predtým čas. logger.debug("--->reportOnlineNodeStatus for line", line); //return; + + //run broadcast //Actual time + addMinutesToTimestamp = 0; + let params = {}; + + let recipient = 2;//2 broadcast, address = 0 + let address = 0;//0 + if(recipient === 2) { - //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); - + 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 = PRIORITY_TYPES.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(PRIORITY_TYPES.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 1;//dimming + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'read dimming'; + //params.debug = true; + + tasks.push(params); + } + + //Prúd + { + let params = getParams(PRIORITY_TYPES.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 = PRIORITY_TYPES.high_priority; + params.info = 'read current'; + //params.debug = true; + + tasks.push(params); + } + + //výkon + { + let params = getParams(PRIORITY_TYPES.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 = PRIORITY_TYPES.high_priority; + params.info = 'read power'; + //params.debug = true; + + tasks.push(params); + } + } + } + },sec*1000); } + function reportOfflineNodeStatus(line) { - logger.debug("--->reportOfflineNodeStatus for line", line); values = {}; @@ -970,7 +910,7 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); } } @@ -982,40 +922,35 @@ exports.install = function(instance) { //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 + line: line, + command: "turnOn", + info: info }; logger.debug("linia", line, obj); - - instance.send(instanceSendTo.dido_controller, obj); + instance.send(SEND_TO.dido_controller, obj); } function turnOffLine(line, info) { let obj = { - line: line, - command: "turnOff", - info: info - }; + line: line, + command: "turnOff", + info: info + }; - logger.debug("linia", line, obj); - - instance.send(instanceSendTo.dido_controller, obj); + logger.debug("linia", line, obj); + instance.send(SEND_TO.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"; @@ -1033,7 +968,7 @@ exports.install = function(instance) { //CRC_ERROR message = "NOK"; error = "CRC_ERROR c1"; - instance.send(instanceSendTo.debug, "CRC_ERROR c1"); + instance.send(SEND_TO.debug, "CRC_ERROR c1"); } if(c2 != bytes[10]) @@ -1041,16 +976,16 @@ exports.install = function(instance) { //CRC_ERROR message = "NOK"; error = "CRC_ERROR c2"; - instance.send(instanceSendTo.debug, "CRC_ERROR c2"); + instance.send(SEND_TO.debug, "CRC_ERROR c2"); } //crc error if(type != "RESPONSE") { - instance.send(instanceSendTo.debug, bytes); - instance.send(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4]); + instance.send(SEND_TO.debug, bytes); + instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]); - //logger.debug(instanceSendTo.debug, "RESPONSE " + type + " - " + bytes[4], bytes); + //logger.debug(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4], bytes); error = "type is: " + type; @@ -1060,16 +995,16 @@ exports.install = function(instance) { return {message: message, type: type, error: error}; } + + //BUILD TASKS// 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; @@ -1079,7 +1014,6 @@ exports.install = function(instance) { { init = true; tasks = []; - logger.debug("-->buildTasks clear tasks"); } else @@ -1103,12 +1037,12 @@ exports.install = function(instance) { let keys = Object.keys(relaysData); for(let i = 0; i < keys.length; i++) { - let line = keys[i];//line is turned off by default + let line = parseInt(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(FLOW.OMS_rvo_name == "Kovalov RVO 2" && line != 0 && init == true) resetLine = true; if(resetLine) { @@ -1116,18 +1050,18 @@ exports.install = function(instance) { 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 + 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 + 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) + //function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) let duskOffset = 20; let dawnOffset = -30; - let sunCalcResult = calculateDuskDown(new Date(), undefined, duskOffset, dawnOffset); + let sunCalcResult = calculateDuskDawn(new Date(), undefined, duskOffset, dawnOffset); console.log(sunCalcResult); monitor.info("--> dusk - dawn", sunCalcResult); @@ -1141,13 +1075,11 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.relay_profile); params.type = "relay"; params.line = line; params.value = value; @@ -1160,8 +1092,7 @@ exports.install = function(instance) { params.addMinutesToTimestamp = 24*60; //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; + params.timePointName = "dusk" 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; @@ -1177,13 +1108,11 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.relay_profile); params.type = "relay"; params.line = line; params.value = value; @@ -1196,8 +1125,7 @@ exports.install = function(instance) { params.addMinutesToTimestamp = 24*60; //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; + params.timePointName = "dusk" 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; @@ -1218,13 +1146,11 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.relay_profile); params.type = "relay"; params.line = line; params.value = value; @@ -1238,8 +1164,7 @@ exports.install = function(instance) { params.addMinutesToTimestamp = 24*60; //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; + params.timePointName = "dawn"; 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; @@ -1255,13 +1180,11 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.relay_profile); params.type = "relay"; params.line = line; params.value = value; @@ -1275,8 +1198,7 @@ exports.install = function(instance) { params.addMinutesToTimestamp = 24*60; //this will be recalculated - params.isDusk = isDusk; - params.isDawn = isDawn; + params.timePointName = "dawn"; 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; @@ -1300,11 +1222,11 @@ exports.install = function(instance) { if(processLine != line) continue; } - try{ + try { - if(profilestr === "") throw ("profile is not defined"); + if(profilestr === "") throw ("Profile is not defined"); let profile = JSON.parse(profilestr); - if(Object.keys(profile).length === 0) throw ("profile is not defined"); + if(Object.keys(profile).length === 0) throw ("Profile is empty"); monitor.info("buildTasks: profile for line", line); monitor.info("profile:", profile); @@ -1312,52 +1234,61 @@ exports.install = function(instance) { let time_points = profile.time_points; if(time_points == undefined) time_points = profile.intervals; + // add name to regular profile timepoint and delete unused end_time key: + time_points.forEach(point => { + point.name = "profileTimepoint" + delete point.end_time; + }); + //monitor.info("buildTasks: time_points", time_points); let currentValue = 0; - if(time_points.length > 0) currentValue = time_points[ time_points.length - 1].value; + if(time_points.length > 0) currentValue = time_points[time_points.length - 1].value; - //create task for tun on + turn off, calculate dusk/down + /** + * if astro_clock is true, we create timepoints, that switch on/off relays accordingly. + * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn + * if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching + */ if(profile.astro_clock == true) { - //let now = new Date().toLocaleString("en-US", {timeZone: "Europe/Bratislava"}); - let sunCalcResult = calculateDuskDown(new Date(), line); - // monitor.info("dusk and dawn sunCalcResult", line, sunCalcResult); + // if astro clock true, we remove all regular profile points + time_points = []; - //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} ); + let sunCalcResult = calculateDuskDawn(new Date(), line); - //aby nam to neostalo svietit + // adding dusk dawn to timpoints + if(profile.dawn_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dawn"], "value": 0, "name":"dawn"}); + if(profile.dusk_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dusk"], "value": 1, "name":"dusk"}); + + //if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit) + //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window if(profile.dawn_lux_sensor == true) { - //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.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} ); + time_points.push({"value": 0, "start_time": strDate, "name": "luxOff"}); } 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.setHours(parseInt(ahours)); + ad.setMinutes(parseInt(aminutes) + profile.dusk_lux_sensor_time_window); ad.setSeconds(0); let strDate = ad.getHours() + ":" + ad.getMinutes(); - time_points.push( {"value": 1, "start_time": strDate} ); + time_points.push({"value": 1, "start_time": strDate, "name": "luxOn"}); + //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing } } @@ -1380,76 +1311,57 @@ exports.install = function(instance) { return ad.getTime() - bd.getTime(); }); + console.log("line timepoints ........", time_points); + monitor.info("-->comming events turn on/off lines:"); for(let t = 0; t < time_points.length; t++) { let start_time = new Date(); + let [hours, minutes, seconds] = time_points[t].start_time.split(':'); - let 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); - } + 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 + //timepoint is in past, we add 24 hours start_time.setDate(start_time.getDate() + 1); } - let params = getParams(priorityTypes.relay_profile); + let params = getParams(PRIORITY_TYPES.relay_profile); params.type = "relay"; - params.line = line; + params.line = parseInt(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; + // it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day + if(time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24*60; - //inak sa cas vypocita dynamicky + //astro timepoints will be recalculated dynamically: + params.timePointName = time_points[t].name; - //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) + // if astro timepoint, we save time window: + if(['luxOn', 'luxOff', 'dusk','dawn'].includes(params.timePointName)) { - 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.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window; + params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window; } + if(params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line; + else if(params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line; + params.debug = true; //turn on/off line tasks.push(params); - monitor.info(params.info, start_time); } @@ -1457,15 +1369,13 @@ exports.install = function(instance) { monitor.info("-->time_points final", line, time_points); //ensure to turn on/off according to calculated value - let params = getParams(priorityTypes.terminal); + let params = getParams(PRIORITY_TYPES.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.timestamp = PRIORITY_TYPES.terminal; params.addMinutesToTimestamp = 0; params.debug = true; @@ -1478,7 +1388,6 @@ exports.install = function(instance) { tasks.push(params); - } catch (error) { if(profilestr !=="" ) { @@ -1509,7 +1418,7 @@ exports.install = function(instance) { // addMinutesToTimestamp = 60*5; addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk - let params = getParams(priorityTypes.node_broadcast); + let params = getParams(PRIORITY_TYPES.node_broadcast); let recipient = 2;//2 broadcast, address = 0 let address = 0;//0 @@ -1518,7 +1427,7 @@ exports.install = function(instance) { address = 0xffffffff;//Broadcast } - let sunCalcResult = calculateDuskDown(); + let sunCalcResult = calculateDuskDawn(); let dusk_hours = sunCalcResult["dusk_hours"]; let dusk_minutes = sunCalcResult["dusk_minutes"]; @@ -1531,7 +1440,7 @@ exports.install = function(instance) { params.register = 6;//Time of dusk - Reg 6 params.rw = 1;//write - let timestampStart = priorityTypes.node_broadcast; + let timestampStart = PRIORITY_TYPES.node_broadcast; //other values params.type = "cmd"; @@ -1550,7 +1459,7 @@ exports.install = function(instance) { // addMinutesToTimestamp = 60*5; addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn - let params = getParams(priorityTypes.node_broadcast); + let params = getParams(PRIORITY_TYPES.node_broadcast); let recipient = 2;//2 broadcast, address = 0 let address = 0;//0 @@ -1559,7 +1468,7 @@ exports.install = function(instance) { address = 0xffffffff;//Broadcast } - let sunCalcResult = calculateDuskDown(); + let sunCalcResult = calculateDuskDawn(); let dawn_hours = sunCalcResult["dawn_hours"]; let dawn_minutes = sunCalcResult["dawn_minutes"]; @@ -1572,7 +1481,7 @@ exports.install = function(instance) { params.register = 7;//Time of dawn - Reg 6 params.rw = 1;//write - let timestampStart = priorityTypes.node_broadcast; + let timestampStart = PRIORITY_TYPES.node_broadcast; //other values params.type = "cmd"; @@ -1589,7 +1498,7 @@ exports.install = function(instance) { //run broadcast //Actual time addMinutesToTimestamp = 5; - let params = getParams(priorityTypes.node_broadcast); + let params = getParams(PRIORITY_TYPES.node_broadcast); let recipient = 2;//2 broadcast, address = 0 let address = 0;//0 @@ -1612,7 +1521,7 @@ exports.install = function(instance) { params.register = 87;//Actual time params.rw = 1;//write - let timestampStart = priorityTypes.node_broadcast; + let timestampStart = PRIORITY_TYPES.node_broadcast; //other values params.type = "cmd"; @@ -1631,7 +1540,7 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.node_broadcast); addMinutesToTimestamp = 15; @@ -1646,7 +1555,7 @@ exports.install = function(instance) { //16 bitový integer s luxami params.byte3 = lux_sensor; params.byte4 = lux_sensor; - params.timestamp = priorityTypes.node_broadcast; + params.timestamp = PRIORITY_TYPES.node_broadcast; params.addMinutesToTimestamp = addMinutesToTimestamp; params.info = "run broadcast: Actual Lux level from cabinet"; params.register = 95;//Actual Lux level from cabinet @@ -1671,7 +1580,7 @@ exports.install = function(instance) { { register = listOfCommands[i]; - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); //core rpc values params.address = address; @@ -1685,7 +1594,7 @@ exports.install = function(instance) { let addMinutesToTimestamp = priorities[register]; - let timestampStart = priorityTypes.node_cmd; //run imediatelly in function runTasks + let timestampStart = PRIORITY_TYPES.node_cmd; //run imediatelly in function runTasks if(addMinutesToTimestamp > 1) { timestampStart = timestampStart + addMinutesToTimestamp * 60000; @@ -1724,12 +1633,12 @@ exports.install = function(instance) { //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); + let params = getParams(PRIORITY_TYPES.fw_detection); params.type = "cmd"; params.register = 4; params.address = 0; - let timestampStart = priorityTypes.fw_detection; + let timestampStart = PRIORITY_TYPES.fw_detection; params.timestamp = timestampStart; params.addMinutesToTimestamp = 5; params.tbname = FLOW.OMS_edgeName; @@ -1743,10 +1652,10 @@ exports.install = function(instance) { //kazdu hodinu skontrolovat nastavenie profilov { - let params = getParams(priorityTypes.fw_detection); + let params = getParams(PRIORITY_TYPES.fw_detection); params.type = "process_profiles"; - let timestampStart = priorityTypes.relay_profile; + let timestampStart = PRIORITY_TYPES.relay_profile; params.timestamp = timestampStart; params.addMinutesToTimestamp = 60;//60 = every hour params.info = "detekcia nespracovaných profilov linie a nodov"; @@ -1758,10 +1667,10 @@ exports.install = function(instance) { { //edge_date_time - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "edge_date_time"; - let timestampStart = priorityTypes.node_cmd; + let timestampStart = PRIORITY_TYPES.node_cmd; params.timestamp = timestampStart; params.addMinutesToTimestamp = 1; params.tbname = FLOW.OMS_edgeName; @@ -1773,10 +1682,10 @@ exports.install = function(instance) { { //edge_date_time - let params = getParams(priorityTypes.node_cmd); + let params = getParams(PRIORITY_TYPES.node_cmd); params.type = "number_of_luminaires"; - let timestampStart = priorityTypes.node_cmd + 1; + let timestampStart = PRIORITY_TYPES.node_cmd + 1; params.timestamp = timestampStart; params.addMinutesToTimestamp = 1; params.tbname = FLOW.OMS_edgeName; @@ -1788,6 +1697,7 @@ exports.install = function(instance) { monitor.info("tasks created:", tasks.length); } + function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) { //let dusk_hours = sunCalcResult["dusk_hours"]; @@ -1832,7 +1742,7 @@ exports.install = function(instance) { if(profile.astro_clock == true) { - let sunCalcResult = calculateDuskDown(now, line); + let sunCalcResult = calculateDuskDawn(now, line); //dawn: usvit/vychod - lux je nad hranicou - vypnem //dusk: zapad pod hranicou - zapnem @@ -1905,14 +1815,6 @@ exports.install = function(instance) { } } - 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) { @@ -1937,10 +1839,10 @@ exports.install = function(instance) { }); } } - + async function runTasks() { - + clearInterval(interval); let currentTimestamp = Date.now(); @@ -1954,7 +1856,7 @@ exports.install = function(instance) { //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); + sendNotification("CMD Manager: calculated Time of dusk", FLOW.OMS_edgeName, "dusk_has_occured", {value: sunCalcResult["dusk"]}, "", SEND_TO.tb, instance); reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time; } } @@ -1962,7 +1864,7 @@ exports.install = function(instance) { var nextDay = new Date(); nextDay.setDate(nextDay.getDate() + 1); - sunCalcResult = calculateDuskDown(nextDay); + sunCalcResult = calculateDuskDawn(nextDay); reportDuskDawn.dusk_time = sunCalcResult.dusk_time; } @@ -1974,7 +1876,7 @@ exports.install = function(instance) { //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); + sendNotification("CMD Manager: calculated Time of dawn", FLOW.OMS_edgeName, "dawn_has_occured", {value: sunCalcResult["dawn"]}, "", SEND_TO.tb, instance); reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time; } } @@ -1982,39 +1884,32 @@ exports.install = function(instance) { var nextDay = new Date(); nextDay.setDate(nextDay.getDate() + 1); - sunCalcResult = calculateDuskDown(nextDay); + sunCalcResult = calculateDuskDawn(nextDay); reportDuskDawn.dawn_time = sunCalcResult.dawn_time; } //-------------------------------------------------------- - //sort tasks - //tasks.sort((a,b) => a.timestamp - b.timestamp ); - + //sort tasks based on 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); - + instance.send(SEND_TO.debug, "no tasks created"); + interval = setInterval(runTasks, LONG_INTERVAL); return; } if(!rsPort.isOpen) { - instance.send(instanceSendTo.debug, "!rsPort.isOpen"); + instance.send(SEND_TO.debug, "!rsPort.isOpen"); //await rsPort.open(); - - //continue } let currentTask = tasks[0]; @@ -2028,47 +1923,36 @@ exports.install = function(instance) { { let params = {...tasks[0]}; - if(FLOW.OMS_maintenance_mode) + //allow terminal commands + if(FLOW.OMS_maintenance_mode && params.type !== "cmd-terminal") { - - //allow terminal commands - if(params.type == "cmd-terminal"); - else - { - interval = setInterval(runTasks, longInterval); - return; - } + interval = setInterval(runTasks, LONG_INTERVAL); + 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(params.addMinutesToTimestamp > 0 || params.timePointName) repeatTask = true; if(repeatTask) { - if(type == "cmd") + if(type === "cmd") { //set next start time automatically tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - } + } } else { - //terminal data... tasks.shift(); } @@ -2114,17 +1998,16 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); return; } } - //kontrola nespracovanych profilov nodov if(type == "process_profiles") { @@ -2160,7 +2043,7 @@ exports.install = function(instance) { //vsetky linie kt. su zapnute, a spracuju sa nespracovane profily nodov loadRelaysData(); - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); return; } @@ -2186,10 +2069,10 @@ exports.install = function(instance) { tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); return; } @@ -2198,56 +2081,69 @@ exports.install = function(instance) { if(type == "relay") { - //ak je dusk, alebo dawn, vypocitame si dynamicky nove values - if(params.isDawn || params.isDusk) + const timePointName = params.timePointName; + const value = params.value; + + // used just in Kovalov RVO 2 + const useProfile = params.useProfile; + + let date = new Date(); + date.setDate(date.getDate() + 1);//next day + + let sunCalcResult; + if(!useProfile) { - 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; - } + sunCalcResult = calculateDuskDawn(date, params.line); } else { - if(tasks[0].addMinutesToTimestamp == 0);// tasks.shift(); - else tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; + //do not use profile, line is there for undefined + sunCalcResult = calculateDuskDawn(date, undefined, params.duskOffset, params.dawnOffset); } + if(timePointName == "dawn") + { + tasks[0].timestamp = sunCalcResult.dawn_time; + } + else if(timePointName == "dusk") + { + tasks[0].timestamp = sunCalcResult.dusk_time; + } + else if(timePointName == "luxOn") + { + tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000; + } + else if(timePointName == "luxOff") + { + tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000; + } + else if(timePointName == "profileTimepoint") + { + tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; + } + + //monitor.info("new relay timepoint sunCalcResult ,,,,,,,,,,", sunCalcResult); + let info; - if(useProfile) info = "aplikovaný bod profilu"; - else info = params.info; + if(!useProfile) info = "aplikovaný bod profilu"; + else info = params.info; //kovalov rvo params.info let message = ""; - if(params.value == 1) + if(value == 1) { turnOnLine(params.line, info); message = "on"; } - else if(params.value == 0) + else if(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 ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", SEND_TO.tb, instance, null ); + if(!useProfile) sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", SEND_TO.tb, instance ); - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); return; } @@ -2285,11 +2181,11 @@ exports.install = function(instance) { if(!disconnectedReport[tbname]) { - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); } - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); return; } @@ -2310,10 +2206,9 @@ exports.install = function(instance) { if(stop) { - interval = setInterval(runTasks, longInterval); + interval = setInterval(runTasks, LONG_INTERVAL); return; } - } let relayStatus = 1; @@ -2341,17 +2236,16 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); - interval = setInterval(runTasks, shortIterval); - + interval = setInterval(runTasks, SHORT_INTERVAL); return; } if(!rsPort.isOpen) { - interval = setInterval(runTasks, longInterval); + interval = setInterval(runTasks, LONG_INTERVAL); return; } @@ -2370,15 +2264,14 @@ exports.install = function(instance) { params.byte4 = 0; } - //set dusk/down for broadcast - + //SET DUSK/DAWN FOR BROADCAST //Time of dusk if(params.register == 6 && params.recipient === 2) { if(params.type != "cmd-terminal") { - let sunCalcResult = calculateDuskDown(); + let sunCalcResult = calculateDuskDawn(); let dusk_hours = sunCalcResult["dusk_hours"]; let dusk_minutes = sunCalcResult["dusk_minutes"]; @@ -2389,7 +2282,7 @@ exports.install = function(instance) { //TODO astrohodiny let dusk = "Time of dusk: " + sunCalcResult["dusk"]; - //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", instanceSendTo.tb, instance, null ); + //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dusk, "", SEND_TO.tb, instance, null ); } } @@ -2398,7 +2291,7 @@ exports.install = function(instance) { { if(params.type != "cmd-terminal") { - let sunCalcResult = calculateDuskDown(); + let sunCalcResult = calculateDuskDawn(); let dawn_hours = sunCalcResult["dawn_hours"]; let dawn_minutes = sunCalcResult["dawn_minutes"]; @@ -2409,7 +2302,7 @@ exports.install = function(instance) { //TODO astrohodiny let dawn = "Time of dawn: " + sunCalcResult["dawn"]; - //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", instanceSendTo.tb, instance, null ); + //sendNotification("CMD Manager: calculated Time of dusk", relaysData[0].tbname, ERRWEIGHT.INFO, dawn, "", SEND_TO.tb, instance, null ); } } @@ -2417,26 +2310,14 @@ exports.install = function(instance) { let register = params.register; - instance.send(instanceSendTo.debug, "address: " + params.address + " register:" + params.register + "type: " + params.type); + instance.send(SEND_TO.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(); @@ -2496,7 +2377,7 @@ exports.install = function(instance) { 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 ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "dimming_profile_was_successfully_received_by_node", {node: params.address}, "", SEND_TO.tb, instance ); logger.debug( "--> profil úspešne odoslaný na node č. " + params.address); nodesData[params.address].processed = true; @@ -2524,17 +2405,17 @@ exports.install = function(instance) { 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" ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", SEND_TO.tb, instance, "rvo_status" ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" ); FLOW.OMS_masterNodeIsResponding = true; } //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 ); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.DEBUG, "odoslanie príkazu z terminálu", params, SEND_TO.tb, instance, null ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "command_was_sent_from_terminal_interface", {}, params, SEND_TO.tb, instance ); } if(params.debug) @@ -2553,7 +2434,7 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); } @@ -2574,11 +2455,11 @@ exports.install = function(instance) { responseObj["bytes"] = data; //params.refFlowdata.data = responseObj; - //instance.send(instanceSendTo.http_response, params.refFlowdata); + //instance.send(SEND_TO.http_response, params.refFlowdata); let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, refFlowdata); + instance.send(SEND_TO.http_response, refFlowdata); } else @@ -2607,13 +2488,13 @@ exports.install = function(instance) { responseObj["bytes"] = data; //params.refFlowdata.data = responseObj; - //instance.send(instanceSendTo.http_response, params.refFlowdata); + //instance.send(SEND_TO.http_response, params.refFlowdata); let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; if(refFlowdata !== undefined) { refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, refFlowdata); + instance.send(SEND_TO.http_response, refFlowdata); } @@ -2634,7 +2515,7 @@ exports.install = function(instance) { responseObj["bytes"] = data; params.refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, params.refFlowdata); + instance.send(SEND_TO.http_response, params.refFlowdata); } } @@ -2642,8 +2523,8 @@ exports.install = function(instance) { 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"); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status"); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status"); logger.debug("master_node_is_not_responding", params); FLOW.OMS_masterNodeIsResponding = false; } @@ -2655,8 +2536,8 @@ exports.install = function(instance) { 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 ); + //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "profil nebol úspešne odoslaný na node č. " + params.address, "", SEND_TO.tb, instance, null ); + sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance ); } //is it node? @@ -2682,11 +2563,11 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); } - //instance.send(instanceSendTo.debug, result); + //instance.send(SEND_TO.debug, result); if(params.hasOwnProperty("debug")) { @@ -2716,13 +2597,13 @@ exports.install = function(instance) { responseObj["message"] = "ERROR WRITE FAILED: " + reason;// //params.refFlowdata.data = responseObj; - //instance.send(instanceSendTo.http_response, params.refFlowdata); + //instance.send(SEND_TO.http_response, params.refFlowdata); let refFlowdata = refFlowdataObj[ params.refFlowdataKey ]; if(refFlowdata !== undefined) { refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, refFlowdata); + instance.send(SEND_TO.http_response, refFlowdata); } @@ -2742,7 +2623,7 @@ exports.install = function(instance) { //responseObj["bytes"] = data; params.refFlowdata.data = responseObj; - instance.send(instanceSendTo.http_response, params.refFlowdata); + instance.send(SEND_TO.http_response, params.refFlowdata); //refFlowdata = undefined; } @@ -2766,8 +2647,8 @@ exports.install = function(instance) { 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"); + //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status"); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status"); logger.debug("master_node_is_not_responding", params); FLOW.OMS_masterNodeIsResponding = false; @@ -2780,8 +2661,8 @@ exports.install = function(instance) { 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 ); + //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "odosielanie profilu na node č. " + params.address + " zlyhalo", "", SEND_TO.tb, instance, null ); + sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance ); } //is it node? @@ -2807,7 +2688,7 @@ exports.install = function(instance) { ] } - //instance.send(instanceSendTo.tb, dataToTb); + //instance.send(SEND_TO.tb, dataToTb); tbHandler.sendToTb(dataToTb, instance); FLOW.OMS_masterNodeIsResponding = false; @@ -2829,11 +2710,11 @@ exports.install = function(instance) { ] } - instance.send(instanceSendTo.tb, dataToTb); + instance.send(SEND_TO.tb, dataToTb); } */ - instance.send(instanceSendTo.debug, reason); + instance.send(SEND_TO.debug, reason); }); } @@ -2845,615 +2726,584 @@ exports.install = function(instance) { logger.debug("currentTask is not processed - task is in the future", currentTask); } - interval = setInterval(runTasks, longInterval); + interval = setInterval(runTasks, LONG_INTERVAL); return; } //console.log("----->runTasks - setInterval", new Date()); - interval = setInterval(runTasks, shortIterval); + interval = setInterval(runTasks, SHORT_INTERVAL); } + //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0" - // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM - // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI + // 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 }); + if(FLOW.OMS_serial_port == "" || FLOW.OMS_serial_port == undefined || FLOW.OMS_serial_port.length === 1) FLOW.OMS_serial_port = "ttymxc4"; + const rsPort = new SerialPort(`/dev/${FLOW.OMS_serial_port}`, { autoOpen: false }); //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit //rsPort.setMaxListeners(0); - rsPort.on('open', async function() { + rsPort.on('open', async function() { logger.debug("CMD manager - rsPort opened sucess"); - await loadRelaysData(); + 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); + await runSyncExec(`stty -F /dev/${FLOW.OMS_serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function (status) { + instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status); - logger.debug(0, "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); + //APP START + let dataToInfoSender = {id: FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name}; + dataToInfoSender.fw_version = FLOW.OMS_edge_fw_version; + dataToInfoSender.startdate = new Date().toISOString().slice(0, 19).replace('T', ' '); + dataToInfoSender.__force__ = true; + + instance.send(SEND_TO.infoSender, dataToInfoSender); - logger.debug(0, "---------------------------->START message send to service", dataToInfoSender); + logger.debug(0, "---------------------------->START message send to service", dataToInfoSender); - //---- + }).catch(function (reason) { + instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason); + }); + }); - 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) { + 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); + instance.send(SEND_TO.debug, err.message); }); - rsPort.on("close", () => { - rsPort.close(); - }); + rsPort.on("close", () => { + rsPort.close(); + }); //loadRelaysData(); rsPort.open(); - instance.on("close", () => { + instance.on("close", () => { clearInterval(interval); - rsPort.close(); - }); + 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); + //instance.send(SEND_TO.debug, "on Data"); + //instance.send(SEND_TO.debug, flowdata); + + //logger.debug(flowdata.data); - //just testing functions - if(flowdata.data == "open") - { - if(!rsPort.isOpen) rsPort.open(); - 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 = []; + //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) + if(tasks.length == 0) + { + + buildTasks(); + + if(rsPort.isOpen) { - - buildTasks(); - - if(rsPort.isOpen) - { - interval = setInterval(runTasks, 100); - } - else - { - instance.send(instanceSendTo.debug, "port is not opened!!!"); - } + interval = setInterval(runTasks, 100); + } + else + { + instance.send(SEND_TO.debug, "port is not opened!!!"); } } - else + } + else + { + //terminal data - object + //logger.debug("flowdata", flowdata.data); + + if(typeof flowdata.data === 'object') { - //terminal data - object - //logger.debug("flowdata", flowdata.data); - - if(typeof flowdata.data === 'object') + //logger.debug("dido", flowdata.data); + if(flowdata.data.hasOwnProperty("sender")) { - //logger.debug("dido", flowdata.data); - if(flowdata.data.hasOwnProperty("sender")) + //data from dido_controller + if(flowdata.data.sender == "dido_controller") { - //data from dido_controller - if(flowdata.data.sender == "dido_controller") + + if(flowdata.data.hasOwnProperty("cmd")) { + let cmd = flowdata.data.cmd; - if(flowdata.data.hasOwnProperty("cmd")) + + if(cmd == "buildTasks") { - let cmd = flowdata.data.cmd; + clearInterval(interval); + logger.debug("-->CMD MANAGER - BUILD TASKS"); + buildTasks(); + + //logger.debug("tasks:"); + //logger.debug(tasks); + + logger.debug("-->CMD MANAGER - RUN TASKS"); + interval = setInterval(runTasks, LONG_INTERVAL); + } + else if(cmd == "reload_relays") + { + loadRelaysData(flowdata.data.line); + + if(flowdata.data.dataChanged) + { + if(!flowdata.data.value) + { + reportOfflineNodeStatus(flowdata.data.line); + } + else + { + reportOnlineNodeStatus(flowdata.data.line); + } + } - if(cmd == "buildTasks") + } + else if(cmd == "rotary_switch_state") + { + //state was changed + if(rotary_switch_state != flowdata.data.value) { - 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(rotary_switch_state == "Off") { - if(!flowdata.data.value) - { - reportOfflineNodeStatus(flowdata.data.line); - } - else - { - reportOnlineNodeStatus(flowdata.data.line); - } + //vyreportovat vsetky svietdla + reportOfflineNodeStatus(); } - + else reportOnlineNodeStatus(); + } - else if(cmd == "rotary_switch_state") + + 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") { - //state was changed - if(rotary_switch_state != flowdata.data.value) + weight = ERRWEIGHT.ERROR; + message = `vypnutý istič línie č. ${line}`; + status = "NOK"; + } + + if(dataChanged) { + + if(relaysData.hasOwnProperty(line)) { - if(rotary_switch_state == "Off") - { - //vyreportovat vsetky svietdla - reportOfflineNodeStatus(); - } - else reportOnlineNodeStatus(); + let tbname = relaysData[line].tbname; - } + if(value == "Off") sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_off_line", {line: line}, "", SEND_TO.tb, instance, "circuit_breaker"); + else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", {line: line}, "", SEND_TO.tb, instance, "circuit_breaker"); - 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); + //report status liniu + let values = { + "status": status + }; + + let dataToTb = { + [tbname]: [ + { + "ts": Date.now(), + "values": values + } + ] } - else reportOnlineNodeStatus(line); - } + + //instance.send(SEND_TO.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); - } + } + else{ + logger.debug("undefined cmd", cmd); } } - - return; } - //data from worksys - if(flowdata.data.hasOwnProperty("topic")) + 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(SEND_TO.debug, flowdata.data); + logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method); + logger.debug("----------------------------"); + + if(entity_type == "street_luminaire"|| entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") { - - 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"|| entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") + if(method == "set_command") { - if(method == "set_command") + + //let command = data.params.command; + let value = data.params.payload.value; + + if(command == "dimming") { - //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 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(PRIORITY_TYPES.high_priority); - if(profile != "") profile = JSON.stringify(profile); - dbNodes.modify({ processed: false, profile: profile }).where("node", node).make(function(builder) { + value = parseInt(value); + if(value > 0) value = value + 128; - builder.callback(function(err, response) { + //set dimming - LUM1_13 - 647 je node linie 1 kt. dobre vidime + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 1;//dimming + params.recipient = 1;//slave + params.byte4 = value; + params.rw = 1;//write + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'set dimming from platform'; + //params.debug = true; - logger.debug("worksys - update node profile done", profile); - if(profile === "") logger.debug("worksys - update node profile done - profile is empty"); + //ak linia je - //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 ); + //debug(params); + logger.debug("dimming", params); - nodesData[node].processed = false; - nodesData[node].profile = profile; + tasks.push(params); - let line = nodesData[node].line; - processNodeProfile(node); + setTimeout(function(){ - }); - }); + //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority + //a pridame aj vyreportovanie dimmingu + { + let params = getParams(PRIORITY_TYPES.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 1;//dimming + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'read dimming (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - vykon + { + let params = getParams(PRIORITY_TYPES.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 76; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'read Input Power (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - prud svietidla + { + let params = getParams(PRIORITY_TYPES.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 75; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'read Input Current (after set dimming from platform)'; + params.debug = true; + + tasks.push(params); + } + + //pridame aj vyreportovanie - power faktor - ucinnik + { + let params = getParams(PRIORITY_TYPES.high_priority); + + params.type = "cmd"; + params.tbname = tbname; + params.address = node; + params.register = 77; + params.recipient = 1;//slave + params.rw = 0;//read + params.timestamp = PRIORITY_TYPES.high_priority; + params.info = 'read power factor - Cos phi (after set dimming from platform)'; + params.debug = true; + + 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, "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); + instance.send(SEND_TO.debug, "undefined command " + command); + logger.debug("undefined command", command); } return; - - } - else{ - instance.send(instanceSendTo.debug, "UNKNOW entity_type " + entity_type); - logger.debug("UNKNOW entity_type", entity_type); } + else if(method == "set_profile") + { + //nastav profil nodu + logger.debug("-->set_profile for node", data.params); + logger.debug("------profile data", profile); + //instance.send(SEND_TO.debug, "set_profile" + command); - return; + 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, SEND_TO.tb, instance, null ); + sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", {node: node}, profile, SEND_TO.tb, instance ); + + nodesData[node].processed = false; + nodesData[node].profile = profile; + + let line = nodesData[node].line; + processNodeProfile(node); + + }); + }); + } + } + } + else + { + + instance.send(SEND_TO.debug, "unknown method " + method); + logger.debug("unknown method", method); + + return; + } } - //terminal - if(!rsPort.isOpen) await rsPort.open(); - - let params = flowdata.data.body; - if(params == undefined) + //nastav profil linie z platformy + else if(entity_type == "edb_line" || entity_type == "edb" || entity_type == "edb_line_ver4" || entity_type == "edb_ver4_se") { - //logger.debug("CMD manager flowdata.data.body is undefined"); + //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(SEND_TO.debug, "worksys - update relay profile done"); + + loadRelaysData(line).then(function (data) { + logger.debug("loadRelaysData DONE for line", line); + buildTasks({processLineProfiles: true, line: line}); + }); + + sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", {line: line}, profile, SEND_TO.tb, instance ); + + }); + }); + 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(SEND_TO.debug, "undefined method " + method); + logger.debug("undefined method", method); + } + 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); - + else + { + instance.send(SEND_TO.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 = PRIORITY_TYPES.terminal; + params.type = "cmd-terminal"; + params.tbname = ""; + params.timestamp = PRIORITY_TYPES.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 @@ -3586,7 +3436,7 @@ setCorrectPlcTimeOnceADay(); ///helper functions -function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) +function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) { if(date === undefined) date = new Date(); @@ -3611,7 +3461,7 @@ function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) let dusk_astro_clock_offset = duskOffset;//minutes let dawn_astro_clock_offset = dawnOffset;//minutes - try{ + try { let profile = JSON.parse(profilestr); if(Object.keys(profile).length === 0) throw ("profile is not defined"); @@ -3671,6 +3521,7 @@ function calculateDuskDown(date, line, duskOffset = 0, dawnOffset = 0) return result; } + function processResponse(register, bytes) { @@ -3796,56 +3647,56 @@ function processResponse(register, bytes) //naklon if(register == 84) { - let temp; - if(byte3 >= 128) - { - temp = (byte3 - 128) * (-1); - } - else - { - temp = byte3; - } + 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_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_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; - } + let inclination_z; + if(byte0 >= 128) + { + inclination_z = (byte0 - 128) * (-1); + } + else + { + inclination_z = byte0; + } - values["temperature"] = temp; + values["temperature"] = temp; - //náklon x - values["inclination_x"] = inclination_x; + //náklon x + values["inclination_x"] = inclination_x; - //náklon y - values["inclination_y"] = inclination_y; + //náklon y + values["inclination_y"] = inclination_y; - //náklon z - values["inclination_z"] = inclination_z; + //náklon z + values["inclination_z"] = inclination_z; } let h = byte3; @@ -3868,7 +3719,6 @@ function processResponse(register, bytes) timestamp = d.getTime(); } - //aktuálny čas if(register == 87) { @@ -3900,13 +3750,13 @@ function processResponse(register, bytes) 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 = []; @@ -3921,7 +3771,7 @@ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4 if (rw === 0) { - cmd = cmd + 0x8000; + cmd = cmd + 0x8000; } //master @@ -3935,24 +3785,24 @@ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4 //recipient if (rec === 3) { - resp.push(0xFF); - resp.push(0xFF); - resp.push(0xFF); - resp.push(0xFF); - resp.push( adresa & 0xFF );//band + 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 ); + 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); + if (rec === 2) + { + resp.push(0xFF); + } + else resp.push(0); } resp.push( (cmd >> 8) & 0xFF);//rshift @@ -3980,3 +3830,441 @@ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4 + + + +const lineTimepointsExample1 = +[ + { start_time: '05:17', value: 0, name: 'dawn' }, + { value: 0, end_time: '13:00', start_time: '05:30' }, + { value: 0, end_time: '20:00', start_time: '13:00' }, + { value: 1, end_time: '05:30', start_time: '20:00' }, + { start_time: '20:19', value: 1, name: 'dusk' } +] + + + +const lineTimepointsExample2 = +[ + { value: 0, end_time: '13:00', start_time: '05:30' }, + { value: 0, start_time: '5:47', name: 'luxOff' }, + { value: 0, end_time: '20:00', start_time: '13:00' }, + { value: 1, end_time: '05:30', start_time: '20:00' }, + { value: 1, start_time: '20:49', name: 'luxOn' } +] + + + + +// SAMPLE DATA + + +const relaysDataExample = +{ + '0': { + line: 0, + tbname: 'jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV', + contactor: 1, + profile: '' + }, + '1': { + line: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + contactor: 1, + profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' + }, + '2': { + line: 2, + tbname: 'jBL12pg63eX4N9P7zy0lJLyEJKmlbkGwZMx0avQV', + contactor: 1, + profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' + }, + '3': { + line: 3, + tbname: 'aAOzENGrvpbe0VoK7D6E1a819PZmdg3nl24JLQMk', + contactor: 1, + profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}' + } +} + + +// [2024-05-08T11:43:33.055] [DEBUG] default - --->reportOfflineNodeStatus for line 2 +// [2024-05-08T11:43:33.055] [DEBUG] default - --->reportOfflineNodeStatus for line 3 +// [2024-05-08T11:43:35.737] [DEBUG] default - -->CMD MANAGER - BUILD TASKS +// [2024-05-08T11:43:35.742] [INFO] monitorLogs - buildTasks - params undefined +// [2024-05-08T11:43:35.743] [DEBUG] default - -->buildTasks clear tasks +// [2024-05-08T11:43:35.744] [INFO] monitorLogs - buildTasks: profile for line 1 +// [2024-05-08T11:43:35.745] [INFO] monitorLogs - profile: { +// intervals: [ { value: 1, end_time: '13:00', start_time: '13:00' } ], +// astro_clock: false, +// dawn_lux_sensor: false, +// dusk_lux_sensor: false, +// dawn_lux_sensor_value: 5, +// dusk_lux_sensor_value: 5, +// dawn_astro_clock_offset: 0, +// dusk_astro_clock_offset: 0, +// dawn_lux_sensor_time_window: 30, +// dusk_lux_sensor_time_window: 30, +// dawn_astro_clock_time_window: 60, +// dusk_astro_clock_time_window: 60 +// } +// [2024-05-08T11:43:35.747] [INFO] monitorLogs - -->comming events turn on/off lines: +// [2024-05-08T11:43:35.748] [INFO] monitorLogs - turn on line: 1 2024-05-08T11:00:00.747Z +// [2024-05-08T11:43:35.749] [INFO] monitorLogs - -->time_points final 1 [ { value: 1, end_time: '13:00', start_time: '13:00' } ] +// [2024-05-08T11:43:35.751] [INFO] monitorLogs - -->currentValue for relay 1 1 +// +// +// typ paramu ...... / cmd + + + +const rpcSwitchOffLine = +{ + "topic": "v1/gateway/rpc", + "content": { + "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV", + "data": { + "id": 8, + "method": "set_command", + "params": { + "entities": [ + { + "entity_type": "edb_line", + "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O" + } + ], + "command": "switch", + "payload": { + "value": false + } + } + } + } +} + +const rpcSetNodeDimming = +{ + "topic": "v1/gateway/rpc", + "content": { + "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV", + "data": { + "id": 10, + "method": "set_command", + "params": { + "entities": [ + { + "entity_type": "street_luminaire", + "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV" + } + ], + "command": "dimming", + "payload": { + "value": 5 + } + } + } + } +} + +const rpcLineProfile = +{ + "topic": "v1/gateway/rpc", + "content": { + "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV", + "data": { + "id": 9, + "method": "set_profile", + "params": { + "entities": [ + { + "entity_type": "edb_line", + "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O" + } + ], + "payload": { + "intervals": [ + { + "value": 0, + "end_time": "20:00", + "start_time": "13:00" + }, + { + "value": 1, + "end_time": "05:30", + "start_time": "20:00" + }, + { + "value": 0, + "end_time": "13:00", + "start_time": "05:30" + } + ], + "astro_clock": true, + "dawn_lux_sensor": false, + "dusk_lux_sensor": false, + "dawn_lux_sensor_value": 5, + "dusk_lux_sensor_value": 5, + "dawn_astro_clock_offset": 0, + "dusk_astro_clock_offset": 0, + "dawn_lux_sensor_time_window": 30, + "dusk_lux_sensor_time_window": 30, + "dawn_astro_clock_time_window": 60, + "dusk_astro_clock_time_window": 60 + } + } + } + } +} + + +const rpcNodeProfile = +{ + "topic": "v1/gateway/rpc", + "content": { + "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV", + "data": { + "id": 11, + "method": "set_profile", + "params": { + "entities": [ + { + "entity_type": "street_luminaire", + "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV" + } + ], + "payload": { + "intervals": [ + { + "cct": 3000, + "value": 0, + "end_time": "17:50", + "start_time": "13:00" + }, + { + "cct": 3000, + "value": 100, + "end_time": "21:30", + "start_time": "17:50" + }, + { + "cct": 3000, + "value": 0, + "end_time": "13:00", + "start_time": "07:10" + }, + { + "cct": 3000, + "value": 50, + "end_time": "00:00", + "start_time": "21:30" + }, + { + "cct": 3000, + "value": 10, + "end_time": "04:30", + "start_time": "00:00" + }, + { + "cct": 3000, + "value": 100, + "end_time": "07:10", + "start_time": "04:30" + } + ], + "astro_clock": true, + "dawn_lux_sensor": false, + "dusk_lux_sensor": false, + "dawn_lux_sensor_value": 5, + "dusk_lux_sensor_value": 5, + "dawn_astro_clock_offset": 30, + "dusk_astro_clock_offset": 20, + "dawn_lux_sensor_time_window": 30, + "dusk_lux_sensor_time_window": 30, + "dawn_astro_clock_time_window": 60, + "dusk_astro_clock_time_window": 60 + } + } + } + } +} + + + + const sunCalcExample = { + dusk_no_offset: '20:18', + dawn_no_offset: '05:19', + dusk: '20:18', + dusk_hours: 20, + dusk_minutes: 18, + dawn: '05:19', + dawn_hours: 5, + dawn_minutes: 19, + dusk_time: 1715278688962, + dawn_time: 1715224744357, + dusk_astro_clock_offset: 0, + dawn_astro_clock_offset: 0 +} + + +// TODO - in runTasks function, when processing tasks, wrong task gets updated +/* +[2024-05-09T20:48:00.200] [DEBUG] default - currentTask is not processed - task is in the future { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 3, + timestamp: 1715280480204, + addMinutesToTimestamp: 0, + type: 'relay', + line: 1, + value: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + timePointName: 'luxOn', + dawn_lux_sensor_time_window: 30, + dusk_lux_sensor_time_window: 30, + info: 'luxOn: turn on line: 1', + debug: true +} +[2024-05-09T20:48:00.302] [INFO] monitorLogs - pparrams ************* { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 3, + timestamp: 1715280480204, + addMinutesToTimestamp: 0, + type: 'relay', + line: 1, + value: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + timePointName: 'luxOn', + dawn_lux_sensor_time_window: 30, + dusk_lux_sensor_time_window: 30, + info: 'luxOn: turn on line: 1', + debug: true +} +new relay task ............ { + address: 4292, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 1, + register: 1, + rw: 0, + priority: 6, + timestamp: 1715280540301, + addMinutesToTimestamp: 1, + type: 'cmd', + tbname: 'jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV', + info: 'generated cmd - buildTasks (node)' +} +[2024-05-09T20:48:00.304] [INFO] monitorLogs - new relay task ............. { + address: 4292, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 1, + register: 1, + rw: 0, + priority: 6, + timestamp: 1715280540301, + addMinutesToTimestamp: 1, + type: 'cmd', + tbname: 'jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV', + info: 'generated cmd - buildTasks (node)' +} +*/ + + + + +/* +~~~~~~~~~~~~~~~~~~~~~pp { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 0, + timestamp: 0, + addMinutesToTimestamp: 0, + type: 'relay', + line: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + value: 0, + debug: true, + info: 'turn off line on startup: 1' +} +deleting task from tasks +++++++++++++++++++++ { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 0, + timestamp: 0, + addMinutesToTimestamp: 0, + type: 'relay', + line: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + value: 0, + debug: true, + info: 'turn off line on startup: 1' +} +[2024-05-10T09:31:36.629] [INFO] monitorLogs - pparrams ************* { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 0, + timestamp: 0, + addMinutesToTimestamp: 0, + type: 'relay', + line: 1, + tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', + value: 0, + debug: true, + info: 'turn off line on startup: 1' +} +else task in relay ????? should be ??? +[2024-05-10T09:31:36.631] [INFO] monitorLogs - new relay task ............. { + address: 0, + byte1: 0, + byte2: 0, + byte3: 0, + byte4: 0, + recipient: 0, + register: -1, + rw: 0, + priority: 0, + timestamp: 0, + addMinutesToTimestamp: 0, + type: 'relay', + line: 2, + tbname: 'jBL12pg63eX4N9P7zy0lJLyEJKmlbkGwZMx0avQV', + value: 1, + debug: true, + info: 'turn on line on startup: 2' +} +*/ diff --git a/flow/dido_controller.js b/flow/dido_controller.js index 60e3976..50bec74 100644 --- a/flow/dido_controller.js +++ b/flow/dido_controller.js @@ -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 = "2023-10-18";//rok-mesiac-den +FLOW.OMS_edge_fw_version = "2024-05-10";//rok-mesiac-den FLOW.OMS_edgeName = ""; FLOW.OMS_maintenance_mode = false; @@ -507,15 +507,18 @@ exports.install = function(instance) { ws.on('error', (err) => { + monitor.info('websocket error, reconnect') instance.send(instanceSendTo.debug, err.message); clearInterval(startRequests); - startRequests = null; + ws = null; + setTimeout(handleWebSocket, 1000); }) ws.onclose = function(){ // connection closed, discard old websocket and create a new one in 5s // stopRequests(); + monitor.info('websocket onclose, reconnect') clearInterval(startRequests); ws = null; console.log("ws is null now, reconnecting..."); @@ -705,7 +708,7 @@ exports.install = function(instance) { // if(!rsPort.isOpen && !ws) if(!rsPort && !ws) { - errLogger.error("di do controller - port or websocket is not opened"); + errLogger.error("dido controller - port or websocket is not opened"); return; } diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js index fd1ac62..52a3af6 100644 --- a/flow/modbus_reader.js +++ b/flow/modbus_reader.js @@ -139,16 +139,16 @@ exports.install = function(instance) { obj.transformResponse(resp, register, obj.deviceAddress); - obj.error = 0; + obj.errors = 0; obj.index++; obj.readAnotherRegister(); }).catch (function () { - console.log("error pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute); + console.log("errors pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute); - obj.error++; - if(obj.error == obj.lengthOfActualDeviceStream) + obj.errors++; + if(obj.errors == obj.lengthOfActualDeviceStream) { instance.send(instanceSendTo.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer @@ -168,7 +168,7 @@ exports.install = function(instance) { numberOfNotResponding[obj.device] = 1; } - obj.error = 0; + obj.errors = 0; numberOfNotResponding[obj.device] += 1; } From 54038a06f8820a126bc1e0d95c8d4a9bf66d5b34 Mon Sep 17 00:00:00 2001 From: rasta5man Date: Tue, 21 May 2024 15:49:42 +0200 Subject: [PATCH 6/9] major updated line switching version 2024-05-10 --- databases/modbus_config.js | 2 +- flow/cmd_manager.js | 401 ++++++++----------------------------- flow/dido_controller.js | 4 + flow/modbus_reader.js | 58 +++--- 4 files changed, 112 insertions(+), 353 deletions(-) diff --git a/databases/modbus_config.js b/databases/modbus_config.js index d63430f..574de9f 100644 --- a/databases/modbus_config.js +++ b/databases/modbus_config.js @@ -1,4 +1,4 @@ -const timeoutInterval = 300000; +const timeoutInterval = 150000; const deviceConfig = [ { device: "em340", diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index b3f9871..9216b4c 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -236,6 +236,17 @@ async function loadSettings() initNotifications(); } +loadSettings(); + + +async function loadNodes() +{ + const responseNodes = await promisifyBuilder(dbNodes.find()); + nodesData = makeMapFromDbResult(responseNodes, "node"); +} + +loadNodes(); + //nastav profil nodu function processNodeProfile(node) @@ -680,7 +691,6 @@ function removeTask(obj) } -loadSettings(); exports.install = function(instance) { @@ -1002,6 +1012,8 @@ exports.install = function(instance) { //report FLOW.OMS_edge_fw_version as fw_version //report date as startdate + //return; + monitor.info("buildTasks - params", params); let processLine; //defined line @@ -1224,6 +1236,10 @@ exports.install = function(instance) { try { + + /** + * we process line profiles: timepoints, astro clock, lux_sensor, offsets ... + */ if(profilestr === "") throw ("Profile is not defined"); let profile = JSON.parse(profilestr); if(Object.keys(profile).length === 0) throw ("Profile is empty"); @@ -1245,6 +1261,7 @@ exports.install = function(instance) { let currentValue = 0; if(time_points.length > 0) currentValue = time_points[time_points.length - 1].value; + /** * if astro_clock is true, we create timepoints, that switch on/off relays accordingly. * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn @@ -1698,121 +1715,88 @@ exports.install = function(instance) { } + /** + * We process line profile, where "astro_clock": true + * example profile: + * + "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 + + * if dawn: if currentTimestamp is in timewindow "dawnTime + and - dawn_lux_sensor_time_window" and lux value >= lux_sensor_value, we switch off the line. + * if dusk: we do oposite + * + * dawn: usvit - lux je nad hranicou - vypnem + * dusk: sumrak - lux je pod hranicou - zapnem + */ 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 line = keys[i]; //line is turned off by default + let profilestr = relaysData[line].profile; + const contactor = relaysData[line].contactor; + + try { let profile = JSON.parse(profilestr); - if(Object.keys(profile).length === 0) throw ("profile is not defined"); + if(Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined"); if(profile.astro_clock == true) { - let sunCalcResult = calculateDuskDawn(now, line); + let sunCalcResult = calculateDuskDawn(now, line); - //dawn: usvit/vychod - lux je nad hranicou - vypnem - //dusk: zapad pod hranicou - zapnem + //usvit + if(profile.dawn_lux_sensor == true) + { + let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut + let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); - //"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) + if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) { - 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 - } + if(lux_sensor_value > profile.dawn_lux_sensor_value) + { + if(contactor) turnOffLine(line, "Profile: dawn - turnOff line according to lux sensor"); + } } + } - //zapad - if(profile.dusk_lux_sensor == true) + //sumrak + if(profile.dusk_lux_sensor == true) + { + let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60); + let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60); + + if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) { - 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"); - // } - - } + if(lux_sensor_value < profile.dusk_lux_sensor_value) + { + if(!contactor) turnOnLine(line, "Profile: dusk - turnOn line according to lux sensor"); + } } - + } } } catch (error) { - //if(profilestr !=="" ) logger.debug(profilestr, error); + if(profilestr !== "" ) monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error); } + } + } @@ -1842,7 +1826,7 @@ exports.install = function(instance) { async function runTasks() { - + clearInterval(interval); let currentTimestamp = Date.now(); @@ -2049,19 +2033,14 @@ exports.install = function(instance) { if(type == "edge_date_time") { + const ts = Date.now(); - //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 values = {"edge_date_time": ts}; let dataToTb = { [tbname]: [ { - "ts": Date.now(), + "ts": ts, "values": values } ] @@ -2069,11 +2048,8 @@ exports.install = function(instance) { tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; - //instance.send(SEND_TO.tb, dataToTb); - tbHandler.sendToTb(dataToTb, instance); - + instance.send(SEND_TO.tb, dataToTb); interval = setInterval(runTasks, SHORT_INTERVAL); - return; } @@ -3832,33 +3808,8 @@ function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4 - -const lineTimepointsExample1 = -[ - { start_time: '05:17', value: 0, name: 'dawn' }, - { value: 0, end_time: '13:00', start_time: '05:30' }, - { value: 0, end_time: '20:00', start_time: '13:00' }, - { value: 1, end_time: '05:30', start_time: '20:00' }, - { start_time: '20:19', value: 1, name: 'dusk' } -] - - - -const lineTimepointsExample2 = -[ - { value: 0, end_time: '13:00', start_time: '05:30' }, - { value: 0, start_time: '5:47', name: 'luxOff' }, - { value: 0, end_time: '20:00', start_time: '13:00' }, - { value: 1, end_time: '05:30', start_time: '20:00' }, - { value: 1, start_time: '20:49', name: 'luxOn' } -] - - - - // SAMPLE DATA - const relaysDataExample = { '0': { @@ -3888,36 +3839,6 @@ const relaysDataExample = } -// [2024-05-08T11:43:33.055] [DEBUG] default - --->reportOfflineNodeStatus for line 2 -// [2024-05-08T11:43:33.055] [DEBUG] default - --->reportOfflineNodeStatus for line 3 -// [2024-05-08T11:43:35.737] [DEBUG] default - -->CMD MANAGER - BUILD TASKS -// [2024-05-08T11:43:35.742] [INFO] monitorLogs - buildTasks - params undefined -// [2024-05-08T11:43:35.743] [DEBUG] default - -->buildTasks clear tasks -// [2024-05-08T11:43:35.744] [INFO] monitorLogs - buildTasks: profile for line 1 -// [2024-05-08T11:43:35.745] [INFO] monitorLogs - profile: { -// intervals: [ { value: 1, end_time: '13:00', start_time: '13:00' } ], -// astro_clock: false, -// dawn_lux_sensor: false, -// dusk_lux_sensor: false, -// dawn_lux_sensor_value: 5, -// dusk_lux_sensor_value: 5, -// dawn_astro_clock_offset: 0, -// dusk_astro_clock_offset: 0, -// dawn_lux_sensor_time_window: 30, -// dusk_lux_sensor_time_window: 30, -// dawn_astro_clock_time_window: 60, -// dusk_astro_clock_time_window: 60 -// } -// [2024-05-08T11:43:35.747] [INFO] monitorLogs - -->comming events turn on/off lines: -// [2024-05-08T11:43:35.748] [INFO] monitorLogs - turn on line: 1 2024-05-08T11:00:00.747Z -// [2024-05-08T11:43:35.749] [INFO] monitorLogs - -->time_points final 1 [ { value: 1, end_time: '13:00', start_time: '13:00' } ] -// [2024-05-08T11:43:35.751] [INFO] monitorLogs - -->currentValue for relay 1 1 -// -// -// typ paramu ...... / cmd - - - const rpcSwitchOffLine = { "topic": "v1/gateway/rpc", @@ -4088,8 +4009,6 @@ const rpcNodeProfile = } } - - const sunCalcExample = { dusk_no_offset: '20:18', dawn_no_offset: '05:19', @@ -4104,167 +4023,3 @@ const rpcNodeProfile = dusk_astro_clock_offset: 0, dawn_astro_clock_offset: 0 } - - -// TODO - in runTasks function, when processing tasks, wrong task gets updated -/* -[2024-05-09T20:48:00.200] [DEBUG] default - currentTask is not processed - task is in the future { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 3, - timestamp: 1715280480204, - addMinutesToTimestamp: 0, - type: 'relay', - line: 1, - value: 1, - tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', - timePointName: 'luxOn', - dawn_lux_sensor_time_window: 30, - dusk_lux_sensor_time_window: 30, - info: 'luxOn: turn on line: 1', - debug: true -} -[2024-05-09T20:48:00.302] [INFO] monitorLogs - pparrams ************* { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 3, - timestamp: 1715280480204, - addMinutesToTimestamp: 0, - type: 'relay', - line: 1, - value: 1, - tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', - timePointName: 'luxOn', - dawn_lux_sensor_time_window: 30, - dusk_lux_sensor_time_window: 30, - info: 'luxOn: turn on line: 1', - debug: true -} -new relay task ............ { - address: 4292, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 1, - register: 1, - rw: 0, - priority: 6, - timestamp: 1715280540301, - addMinutesToTimestamp: 1, - type: 'cmd', - tbname: 'jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV', - info: 'generated cmd - buildTasks (node)' -} -[2024-05-09T20:48:00.304] [INFO] monitorLogs - new relay task ............. { - address: 4292, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 1, - register: 1, - rw: 0, - priority: 6, - timestamp: 1715280540301, - addMinutesToTimestamp: 1, - type: 'cmd', - tbname: 'jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV', - info: 'generated cmd - buildTasks (node)' -} -*/ - - - - -/* -~~~~~~~~~~~~~~~~~~~~~pp { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 0, - timestamp: 0, - addMinutesToTimestamp: 0, - type: 'relay', - line: 1, - tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', - value: 0, - debug: true, - info: 'turn off line on startup: 1' -} -deleting task from tasks +++++++++++++++++++++ { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 0, - timestamp: 0, - addMinutesToTimestamp: 0, - type: 'relay', - line: 1, - tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', - value: 0, - debug: true, - info: 'turn off line on startup: 1' -} -[2024-05-10T09:31:36.629] [INFO] monitorLogs - pparrams ************* { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 0, - timestamp: 0, - addMinutesToTimestamp: 0, - type: 'relay', - line: 1, - tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O', - value: 0, - debug: true, - info: 'turn off line on startup: 1' -} -else task in relay ????? should be ??? -[2024-05-10T09:31:36.631] [INFO] monitorLogs - new relay task ............. { - address: 0, - byte1: 0, - byte2: 0, - byte3: 0, - byte4: 0, - recipient: 0, - register: -1, - rw: 0, - priority: 0, - timestamp: 0, - addMinutesToTimestamp: 0, - type: 'relay', - line: 2, - tbname: 'jBL12pg63eX4N9P7zy0lJLyEJKmlbkGwZMx0avQV', - value: 1, - debug: true, - info: 'turn on line on startup: 2' -} -*/ diff --git a/flow/dido_controller.js b/flow/dido_controller.js index 50bec74..0952350 100644 --- a/flow/dido_controller.js +++ b/flow/dido_controller.js @@ -864,6 +864,10 @@ exports.install = function(instance) { { deviceStatuses["em"] = "OK"; } + else + { + return; + } const updateStatus = checkFinalRVOStatus(); if(updateStatus) values.status = "OK"; diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js index 52a3af6..898816e 100644 --- a/flow/modbus_reader.js +++ b/flow/modbus_reader.js @@ -16,17 +16,12 @@ exports.readme = ` 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 DELAY_BETWEEN_DEVICES = 10000; -const instanceSendTo = { +const SEND_TO = { debug: 0, dido_controller: 1, tb: 2 @@ -49,9 +44,9 @@ exports.install = function(instance) { 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 + // we need to go always around for all devices. So we need index value, device address, as well as number of registers for single device + this.deviceAddress = null; // device address (1 - EM340 and 2 for twilight_sensor) + this.indexInDeviceConfig = 0; // first item in deviceConfig this.lengthOfActualDeviceStream = null; this.device = null; @@ -69,7 +64,7 @@ exports.install = function(instance) { // 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.clients[deviceConfig[i].deviceAddress] = new modbus.client.RTU(this.socket, deviceConfig[i].deviceAddress, 2000); // 2000 is timeout in register request, default is 5000, which is too long } this.socket.on('error', function(e) { @@ -133,13 +128,13 @@ exports.install = function(instance) { { message = "twilight_sensor_ok"; } - message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", instanceSendTo.tb, instance); + message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", SEND_TO.tb, instance); delete numberOfNotResponding[obj.device]; } - obj.transformResponse(resp, register, obj.deviceAddress); + obj.transformResponse(resp, register); - obj.errors = 0; + //obj.errors = 0; obj.index++; obj.readAnotherRegister(); @@ -150,7 +145,7 @@ exports.install = function(instance) { obj.errors++; if(obj.errors == obj.lengthOfActualDeviceStream) { - instance.send(instanceSendTo.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer + instance.send(SEND_TO.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer //todo - neposlalo notification, ked sme vypojili twilight a neposle to do tb, ale do dido ?? if(!numberOfNotResponding.hasOwnProperty(obj.device)) @@ -164,7 +159,7 @@ exports.install = function(instance) { { message = "electrometer_nok"; } - message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", instanceSendTo.tb, instance); + message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", SEND_TO.tb, instance); numberOfNotResponding[obj.device] = 1; } @@ -176,6 +171,12 @@ exports.install = function(instance) { depth: null })) + // if reading out of device's last register returns error, we send accumulated allValues to dido_controller (if allValues are not an empty object) + if(obj.index + 1 >= obj.lengthOfActualDeviceStream) + { + if(!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, {values: obj.allValues}); + obj.allValues = {}; + } obj.index++; obj.readAnotherRegister(); }) @@ -187,7 +188,7 @@ exports.install = function(instance) { else this.setNewStream(); } - transformResponse = (response, register, deviceAddress) => { + transformResponse = (response, register) => { for (let i = 0; i < this.lengthOfActualDeviceStream; i++) { @@ -198,11 +199,11 @@ exports.install = function(instance) { let multiplier = a.multiplier; let value = this.calculateValue(response, multiplier); - // console.log(deviceAddress, register, tbName, tbAttribute, response, a.multiplier, value); + // console.log(register, tbName, tbAttribute, response, a.multiplier, value); // if(tbName == undefined) return; - if(this.index + 1 + this.errors < this.lengthOfActualDeviceStream) + if(this.index + 1 < this.lengthOfActualDeviceStream) { this.allValues[tbAttribute] = value; return; @@ -215,7 +216,7 @@ exports.install = function(instance) { this.checkNullVoltage(values); - instance.send(instanceSendTo.dido_controller, {values: values}); + instance.send(SEND_TO.dido_controller, {values: values}); this.allValues = {}; break; @@ -227,8 +228,6 @@ exports.install = function(instance) { setNewStream = () => { - // console.log('------------',this.lengthOfActualDeviceStream, this.index); - // console.log('------------',this.indexInDeviceConfig, deviceConfig.length); if(this.lengthOfActualDeviceStream == this.index) { if(this.indexInDeviceConfig + 1 == deviceConfig.length) @@ -260,13 +259,13 @@ exports.install = function(instance) { // ] // }; - // instance.send(instanceSendTo.tb, dataToTB); + // instance.send(SEND_TO.tb, dataToTB); // const dataToDiDo = { // values: values // } - // instance.send(instanceSendTo.dido_controller, dataToDiDo); + // instance.send(SEND_TO.dido_controller, dataToDiDo); // } @@ -314,27 +313,28 @@ exports.install = function(instance) { 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 ); + sendNotification("modbus_citys: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase ); // console.log('no voltage') } else { FLOW.OMS_no_voltage.delete(phase); // console.log('voltage detected') - sendNotification("modbus_citys: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", instanceSendTo.tb, instance, "voltage" + phase); + sendNotification("modbus_citys: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.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; - } } + const isObjectEmpty = (objectName) => { + return Object.keys(objectName).length === 0 && objectName.constructor === Object; + } + setTimeout(() => { const newSocket = new SocketWithClients(); tbName = FLOW.OMS_rvo_tbname; }, 25000); } + From f4ffef94b986f2e49e6523acec5b95fc5f485dad Mon Sep 17 00:00:00 2001 From: rasta5man Date: Thu, 20 Jun 2024 17:56:49 +0200 Subject: [PATCH 7/9] kovalov part delete --- flow/cmd_manager.js | 204 ++------------------------------------------ 1 file changed, 5 insertions(+), 199 deletions(-) diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 9216b4c..3a03acc 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -58,8 +58,8 @@ const process = require('process'); //TODO - to remove? // runTasks intervals -const SHORT_INTERVAL = 50; -const LONG_INTERVAL = 500; +const SHORT_INTERVAL = 30; +const LONG_INTERVAL = 300; //send data to following instances: const SEND_TO = { @@ -1052,183 +1052,6 @@ exports.install = function(instance) { let line = parseInt(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 calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) - let duskOffset = 20; - let dawnOffset = -30; - let sunCalcResult = calculateDuskDawn(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 dusk_time = sunCalcResult.dusk_time; - if(dusk_time < now.getTime()) dusk_time = dusk_time + 24*60*60*1000;//1den - - let params = getParams(PRIORITY_TYPES.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.timePointName = "dusk" - - 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 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(PRIORITY_TYPES.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.timePointName = "dusk" - - 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 dawn_time = sunCalcResult.dawn_time; - if(dawn_time < now.getTime()) dawn_time = dawn_time + 24*60*60*1000;//1den - - let params = getParams(PRIORITY_TYPES.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.timePointName = "dawn"; - - 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 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(PRIORITY_TYPES.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.timePointName = "dawn"; - - 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; @@ -1236,7 +1059,6 @@ exports.install = function(instance) { try { - /** * we process line profiles: timepoints, astro clock, lux_sensor, offsets ... */ @@ -2060,22 +1882,11 @@ exports.install = function(instance) { const timePointName = params.timePointName; const value = params.value; - // used just in Kovalov RVO 2 - const useProfile = params.useProfile; - let date = new Date(); date.setDate(date.getDate() + 1);//next day let sunCalcResult; - if(!useProfile) - { - sunCalcResult = calculateDuskDawn(date, params.line); - } - else - { - //do not use profile, line is there for undefined - sunCalcResult = calculateDuskDawn(date, undefined, params.duskOffset, params.dawnOffset); - } + sunCalcResult = calculateDuskDawn(date, params.line); if(timePointName == "dawn") { @@ -2098,12 +1909,7 @@ exports.install = function(instance) { tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; } - //monitor.info("new relay timepoint sunCalcResult ,,,,,,,,,,", sunCalcResult); - - let info; - if(!useProfile) info = "aplikovaný bod profilu"; - else info = params.info; //kovalov rvo params.info - + let info = "aplikovaný bod profilu"; let message = ""; if(value == 1) { @@ -2117,7 +1923,7 @@ exports.install = function(instance) { } //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", SEND_TO.tb, instance, null ); - if(!useProfile) sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", SEND_TO.tb, instance ); + sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", SEND_TO.tb, instance ); interval = setInterval(runTasks, SHORT_INTERVAL); return; From 8929cc3a534f793eabf184b3ab67b1b438b09542 Mon Sep 17 00:00:00 2001 From: rasta5man Date: Mon, 9 Sep 2024 12:32:34 +0200 Subject: [PATCH 8/9] actual working Senica Rvo code 09/2024 --- databases/modbus_config.js | 3 +- databases/notifications.table | 5 +- flow/cmd_manager.js | 120 ++---- flow/designer.json | 678 +++++++++++++++++++++++----------- flow/dido_controller.js | 174 ++++----- flow/modbus_reader.js | 72 ++-- flow/slack_filter.js | 187 ++++++++++ 7 files changed, 810 insertions(+), 429 deletions(-) create mode 100644 flow/slack_filter.js diff --git a/databases/modbus_config.js b/databases/modbus_config.js index 574de9f..b73116a 100644 --- a/databases/modbus_config.js +++ b/databases/modbus_config.js @@ -1,4 +1,5 @@ const timeoutInterval = 150000; + const deviceConfig = [ { device: "em340", @@ -110,4 +111,4 @@ const deviceConfig = [ } ]; -module.exports = { timeoutInterval, deviceConfig }; +module.exports = { timeoutInterval, deviceConfig }; \ No newline at end of file diff --git a/databases/notifications.table b/databases/notifications.table index b207fe7..a0590d3 100644 --- a/databases/notifications.table +++ b/databases/notifications.table @@ -31,4 +31,7 @@ key:string|weight:string|sk:string|en:string +|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 ++|twilight_sensor_ok|NOTICE|Sensor súmraku znovu odpovedá|Twilight sensor is responding again|............... ++|lamps_have_turned_on|NOTICE|Lampy sa zapli|Lamps have turned on|............... ++|lamps_have_turned_off|NOTICE|Lampy sa vypli|Lamps have turned off|............... ++|flow_restart|NOTICE|Restart flowu|Flow has been restarted|............... diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 3a03acc..48b4987 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -280,30 +280,20 @@ function processNodeProfile(node) try{ nodeProfile = JSON.parse( profile ); if(Object.keys(nodeProfile).length === 0) throw ("profile is not defined"); - } catch (error) {} - - //test reset profilu - //nodeProfile = undefined; + } catch (error) { + logger.debug("Error parsing node profile", error); + } logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile); - //return; - - //let timestamp = PRIORITY_TYPES.node_cmd; - - //let now = new Date(); - //now.setSeconds(now.getSeconds() + 10); - //let timestamp = now.getTime(); let timestamp = PRIORITY_TYPES.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 @@ -318,7 +308,7 @@ function processNodeProfile(node) params.byte1 = 0; params.byte2 = 0; params.byte3 = 0; - params.byte4 = 32; + params.byte4 = 96; params.recipient = 1; params.register = 8; params.rw = 1;//write @@ -347,7 +337,7 @@ function processNodeProfile(node) params.byte1 = 0; params.byte2 = 0; params.byte3 = 0; - params.byte4 = 32; + params.byte4 = 96; params.recipient = 1; params.register = 8; params.rw = 1;//write @@ -615,7 +605,7 @@ function processNodeProfile(node) 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 + if(nodeProfile.dawn_lux_sensor == true)//usvit { bits.push(1); } @@ -765,7 +755,7 @@ exports.install = function(instance) { if(key == "0") continue; if(line != undefined) { - //ak sa jedna o update profilu linie - pozor di_co_controller posiela command pre loadRelaysData + //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData if(line != value.line ) continue; } @@ -1254,28 +1244,20 @@ exports.install = function(instance) { { //run broadcast Time of dusk - // addMinutesToTimestamp = 60*5; addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk let params = getParams(PRIORITY_TYPES.node_broadcast); - let recipient = 2;//2 broadcast, address = 0 - let address = 0;//0 - if(recipient === 2) - { - address = 0xffffffff;//Broadcast - } - let sunCalcResult = calculateDuskDawn(); let dusk_hours = sunCalcResult["dusk_hours"]; let dusk_minutes = sunCalcResult["dusk_minutes"]; - params.address = address;//broadcast + params.address = 0xffffffff;//broadcast params.byte1 = dusk_hours;//h params.byte2 = dusk_minutes;//m params.byte3 = 0;//s params.byte4 = 0; - params.recipient = recipient; + params.recipient = 2;//2 broadcast, params.register = 6;//Time of dusk - Reg 6 params.rw = 1;//write @@ -1300,23 +1282,16 @@ exports.install = function(instance) { let params = getParams(PRIORITY_TYPES.node_broadcast); - let recipient = 2;//2 broadcast, address = 0 - let address = 0;//0 - if(recipient === 2) - { - address = 0xffffffff;//Broadcast - } - let sunCalcResult = calculateDuskDawn(); let dawn_hours = sunCalcResult["dawn_hours"]; let dawn_minutes = sunCalcResult["dawn_minutes"]; - params.address = address;//broadcast + params.address = 0xffffffff;//broadcast params.byte1 = dawn_hours;//h params.byte2 = dawn_minutes;//m params.byte3 = 0;//s params.byte4 = 0; - params.recipient = recipient; + params.recipient = 2; //2 broadcast params.register = 7;//Time of dawn - Reg 6 params.rw = 1;//write @@ -1332,31 +1307,23 @@ exports.install = function(instance) { tasks.push(params); } - { //run broadcast //Actual time addMinutesToTimestamp = 5; let params = getParams(PRIORITY_TYPES.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.address = 0xffffffff;//broadcast params.byte1 = hours;//h params.byte2 = minutes;//m params.byte3 = seconds;//s params.byte4 = 0; - params.recipient = recipient; + params.recipient = 2; //2 broadcast params.register = 87;//Actual time params.rw = 1;//write @@ -1370,37 +1337,8 @@ exports.install = function(instance) { 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(PRIORITY_TYPES.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 = PRIORITY_TYPES.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 @@ -1909,7 +1847,7 @@ exports.install = function(instance) { tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000; } - let info = "aplikovaný bod profilu"; + let info = "aplikovany bod profilu"; let message = ""; if(value == 1) { @@ -2099,8 +2037,9 @@ exports.install = function(instance) { let resp = com_generic(params.address, params.recipient, params.rw, params.register, params.name, params.byte1, params.byte2, params.byte3, params.byte4); let readBytes = 11; + let timeout = 5000; - await writeData(rsPort, resp, readBytes).then(function (data) { + await writeData(rsPort, resp, readBytes, timeout).then(function (data) { endTime = new Date(); var timeDiff = endTime - startTime; @@ -2690,8 +2629,31 @@ exports.install = function(instance) { { lux_sensor = parseInt(flowdata.data.value); - //process profiles - turnOnOffLinesAccordingToLuxSensor(lux_sensor); + // POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ?? + if(lux_sensor < 100) + { + + // we send lux_sensor value to all nodes: + let params = getParams(PRIORITY_TYPES.node_broadcast); + + params.recipient = 2;//2 broadcast, address = 0 + params.address = 0xffffffff;//Broadcast + + let ba = longToByteArray(lux_sensor); + + params.byte3 = ba[1];//msb + params.byte4 = ba[0]; + params.timestamp = PRIORITY_TYPES.node_broadcast; + params.info = "run broadcast: Actual Lux level from cabinet"; + params.register = 95;//Actual Lux level from cabinet + params.rw = 1;//write + + tasks.push(params); + + + //process profiles + turnOnOffLinesAccordingToLuxSensor(lux_sensor); + } } else if(cmd == "state_of_breaker") { diff --git a/flow/designer.json b/flow/designer.json index 7cb3ebb..7d57d69 100644 --- a/flow/designer.json +++ b/flow/designer.json @@ -25,8 +25,8 @@ "component": "debug", "tab": "1611921777196", "name": "ERROR", - "x": 404, - "y": 36, + "x": 401, + "y": 31, "connections": {}, "disabledio": { "input": [], @@ -36,13 +36,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#DA4453", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#DA4453", + "notes": "" }, { "id": "1612776786008", @@ -87,14 +87,14 @@ "text": "Connected", "color": "green" }, - "color": "#888600", - "notes": "", "options": { "username": "", "clientid": "", "port": "1883", "host": "" - } + }, + "color": "#888600", + "notes": "" }, { "id": "1612778461252", @@ -123,11 +123,11 @@ "text": "tb-push", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "tb-push" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1612783322136", @@ -147,13 +147,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1615551060773", @@ -173,13 +173,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#DA4453", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#DA4453", + "notes": "" }, { "id": "1615563373927", @@ -199,13 +199,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#DA4453", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#DA4453", + "notes": "" }, { "id": "1615566865233", @@ -223,11 +223,11 @@ "text": "tb-push", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "tb-push" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1615798582262", @@ -247,21 +247,21 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1615802995322", "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 400.8833312988281, - "y": 484.3500061035156, + "x": 398.8833312988281, + "y": 528.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -270,24 +270,24 @@ "output": [] }, "state": { - "text": "Enabled", + "text": "Disabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, - "enabled": true - } + "enabled": false + }, + "color": "#967ADC", + "notes": "" }, { "id": "1615809128443", "component": "debug", "tab": "1611921777196", "name": "Debug", - "x": 405.8833312988281, - "y": 566.3500061035156, + "x": 401.8833312988281, + "y": 625.3500061035156, "connections": {}, "disabledio": { "input": [ @@ -299,21 +299,21 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1615809595184", "component": "virtualwireout", "tab": "1611921777196", "name": "tb-push", - "x": 401.8833312988281, - "y": 306.25, + "x": 400.8833312988281, + "y": 328.25, "connections": {}, "disabledio": { "input": [], @@ -323,11 +323,11 @@ "text": "tb-push", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "tb-push" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1616165795916", @@ -356,9 +356,6 @@ "text": "Listening", "color": "green" }, - "color": "#5D9CEC", - "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", - "cloning": false, "options": { "timeout": 10, "cachepolicy": 0, @@ -373,7 +370,10 @@ 10000 ], "emptyresponse": false - } + }, + "color": "#5D9CEC", + "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__", + "cloning": false }, { "id": "1616165824813", @@ -391,11 +391,11 @@ "text": "", "color": "gray" }, - "color": "#5D9CEC", - "notes": "", "options": { "datatype": "json" - } + }, + "color": "#5D9CEC", + "notes": "" }, { "id": "1617104731852", @@ -415,13 +415,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1617114651703", @@ -446,19 +446,19 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "data": "{line: 3, command: \"turnOff\", force: true}", "datatype": "object" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1617115013095", "component": "virtualwireout", "tab": "1615551125555", "name": "tb-push", - "x": 747, + "x": 741, "y": 736, "connections": {}, "disabledio": { @@ -469,11 +469,11 @@ "text": "tb-push", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "tb-push" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1617178324650", @@ -491,13 +491,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1617179044099", @@ -522,12 +522,12 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "datatype": "object", "data": "{table: \"konsberg_production_line_operations_error\", startFrom: 1, delimiter: \";\", uniqueColumn: \"\", path: \"flow/operations_error.csv\", mapImport: {0: \"production_line\",\t1: \"operation\", 2: \"error_type\", 3: \"error_code\", 4: \"error_text\", 5: \"error_text_user_defined\"}}" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1617180390661", @@ -552,11 +552,11 @@ "text": "", "color": "gray" }, - "color": "#2134B0", - "notes": "", "options": { "edge": "undefined" - } + }, + "color": "#2134B0", + "notes": "" }, { "id": "1617197763128", @@ -574,9 +574,9 @@ "text": "", "color": "gray" }, + "options": {}, "color": "#704cff", - "notes": "", - "options": {} + "notes": "" }, { "id": "1617284749681", @@ -601,12 +601,12 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "datatype": "string", "data": "profile_nodes" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1618235171399", @@ -631,11 +631,11 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "data": "run" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1618300858252", @@ -653,13 +653,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1618300863816", @@ -679,13 +679,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1618393583970", @@ -703,11 +703,11 @@ "text": "from-dido-controller", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "from-dido-controller" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1618393674428", @@ -732,11 +732,11 @@ "text": "platform-rpc-call", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "platform-rpc-call" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1618393759854", @@ -765,11 +765,11 @@ "text": "cmd_to_dido", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "cmd_to_dido" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1618393827655", @@ -787,11 +787,11 @@ "text": "cmd_to_dido", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "cmd_to_dido" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1618558465485", @@ -809,11 +809,11 @@ "text": "platform-rpc-call", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "platform-rpc-call" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1618572059773", @@ -838,12 +838,12 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "datatype": "object", "data": "{line: 1, command: \"turnOn\", force: true}" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1619515097737", @@ -896,9 +896,9 @@ "text": "", "color": "gray" }, + "options": {}, "color": "#5D9CEC", - "notes": "", - "options": {} + "notes": "" }, { "id": "1619605019281", @@ -927,9 +927,6 @@ "text": "Listening", "color": "green" }, - "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, "options": { "timeout": 5, "cachepolicy": 0, @@ -943,7 +940,10 @@ "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", @@ -968,12 +968,12 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "data": "{command: \"turnOnAlarm\"}", "datatype": "object" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1619784812964", @@ -998,20 +998,20 @@ "text": "", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "data": "{command: \"turnOffAlarm\"}", "datatype": "object" - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1621340721628", "component": "virtualwireout", "tab": "1611921777196", "name": "modbus_to_dido", - "x": 403, - "y": 394, + "x": 399, + "y": 433, "connections": {}, "disabledio": { "input": [], @@ -1021,11 +1021,11 @@ "text": "modbus_to_dido", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "modbus_to_dido" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1622640022885", @@ -1050,9 +1050,6 @@ "text": "Listening", "color": "green" }, - "color": "#5D9CEC", - "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, "options": { "timeout": 5, "cachepolicy": 0, @@ -1065,7 +1062,10 @@ "post", 5000 ] - } + }, + "color": "#5D9CEC", + "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 }, { "id": "1622640073521", @@ -1090,11 +1090,11 @@ "text": "", "color": "gray" }, - "color": "#2134B0", - "notes": "", "options": { "edge": "undefined" - } + }, + "color": "#2134B0", + "notes": "" }, { "id": "1622641420685", @@ -1112,9 +1112,9 @@ "text": "", "color": "gray" }, + "options": {}, "color": "#5D9CEC", - "notes": "", - "options": {} + "notes": "" }, { "id": "1634303504177", @@ -1136,15 +1136,15 @@ "output": [] }, "state": { - "text": "801.23 MB / 987.80 MB", + "text": "834.19 MB / 985.68 MB", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "enabled": true, "interval": 30000 - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1634303533779", @@ -1166,16 +1166,16 @@ "output": [] }, "state": { - "text": "5.90 GB / 7.26 GB", + "text": "5.84 GB / 7.26 GB", "color": "gray" }, - "color": "#F6BB42", - "notes": "", "options": { "enabled": true, "path": "/", "interval": 30000 - } + }, + "color": "#F6BB42", + "notes": "" }, { "id": "1634303595494", @@ -1204,11 +1204,11 @@ "text": "send-to-services", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "send-to-services" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1634303602169", @@ -1226,11 +1226,11 @@ "text": "send-to-services", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "send-to-services" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1634303685503", @@ -1248,11 +1248,11 @@ "text": "send-to-services", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "send-to-services" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1634303743260", @@ -1278,13 +1278,13 @@ "text": "", "color": "gray" }, - "color": "#5D9CEC", - "notes": "", "options": { "stringify": "json", "method": "POST", "url": "http://192.168.252.2:8004/sentmessage" - } + }, + "color": "#5D9CEC", + "notes": "" }, { "id": "1634463186563", @@ -1304,13 +1304,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1634464580289", @@ -1339,13 +1339,13 @@ "text": "", "color": "gray" }, - "color": "#656D78", - "notes": "", "options": { "keepmessage": true, "code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);", "outputs": 1 - } + }, + "color": "#656D78", + "notes": "" }, { "id": "1634465243324", @@ -1365,13 +1365,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1634465281992", @@ -1400,13 +1400,13 @@ "text": "", "color": "gray" }, - "color": "#656D78", - "notes": "", "options": { "keepmessage": true, "code": "value.sender = \"ram\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.memory_total = (total).toFixed(0) + ' MB';\n//value.memory_free = (free).toFixed(0) + ' MB';\n//value.memory_used = (used).toFixed(0) + ' MB';\n\nresponse.memory_total = value.total;\nresponse.memory_free = value.free;\nresponse.memory_used = value.used;\n\nsend(0, response);", "outputs": 1 - } + }, + "color": "#656D78", + "notes": "" }, { "id": "1634465338103", @@ -1426,13 +1426,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1634465821120", @@ -1461,13 +1461,13 @@ "text": "", "color": "gray" }, - "color": "#656D78", - "notes": "", "options": { "keepmessage": true, "code": "value.sender = \"hdd\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.hdd_total = (total).toFixed(0) + ' MB';\n//value.hdd_free = (free).toFixed(0) + ' MB';\n//value.used = (used).toFixed(0) + ' MB';\n\nresponse.hdd_total = value.total;\nresponse.hdd_free = value.free;\nresponse.hdd_used = value.used;\n\nsend(0, response);", "outputs": 1 - } + }, + "color": "#656D78", + "notes": "" }, { "id": "1634465892500", @@ -1487,13 +1487,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1634484067516", @@ -1513,13 +1513,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1634488120710", @@ -1548,11 +1548,11 @@ "text": "", "color": "gray" }, - "color": "#2134B0", - "notes": "", "options": { "edge": "undefined" - } + }, + "color": "#2134B0", + "notes": "" }, { "id": "1635327431236", @@ -1572,13 +1572,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1635936391935", @@ -1596,11 +1596,11 @@ "text": "send-to-services", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "send-to-services" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1637069803394", @@ -1622,11 +1622,9 @@ "output": [] }, "state": { - "text": "11.7% / 69.98 MB", + "text": "1.9% / 86.94 MB", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "monitorfiles": true, "monitorconnections": true, @@ -1634,7 +1632,9 @@ "monitorconsumption": true, "enabled": true, "interval": 30000 - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1683664161036", @@ -1654,13 +1654,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1683981346282", @@ -1689,11 +1689,11 @@ "text": "from-dido-controller", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "from-dido-controller" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1684055037116", @@ -1713,13 +1713,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1684060205000", @@ -1739,13 +1739,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1684179110403", @@ -1753,7 +1753,7 @@ "tab": "1611921777196", "name": "MDBToDido", "x": 401, - "y": 125, + "y": 118, "connections": {}, "disabledio": { "input": [], @@ -1763,13 +1763,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1699963668903", @@ -1810,11 +1810,11 @@ "text": "", "color": "gray" }, - "color": "#2134B0", - "notes": "", "options": { "edge": "undefined" - } + }, + "color": "#2134B0", + "notes": "" }, { "id": "1699964678894", @@ -1843,11 +1843,11 @@ "text": "modbus_to_dido", "color": "gray" }, - "color": "#303E4D", - "notes": "", "options": { "wirename": "modbus_to_dido" - } + }, + "color": "#303E4D", + "notes": "" }, { "id": "1699964793925", @@ -1867,13 +1867,13 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" }, { "id": "1699965957410", @@ -1897,6 +1897,10 @@ { "index": "0", "id": "1684179110403" + }, + { + "index": "0", + "id": "1717441414646" } ], "2": [ @@ -1918,17 +1922,17 @@ "text": "", "color": "gray" }, + "options": {}, "color": "#2134B0", - "notes": "", - "options": {} + "notes": "" }, { "id": "1700411878636", "component": "thermometer", "tab": "1611921777196", "name": "Thermometer", - "x": 103.75, - "y": 408, + "x": 107.75, + "y": 449, "connections": { "0": [ { @@ -1961,9 +1965,9 @@ "text": "", "color": "gray" }, + "options": {}, "color": "#5CB36D", - "notes": "", - "options": {} + "notes": "" }, { "id": "1714752862828", @@ -1971,7 +1975,7 @@ "tab": "1611921777196", "name": "MDBToTb", "x": 402, - "y": 215, + "y": 228, "connections": {}, "disabledio": { "input": [], @@ -1981,14 +1985,248 @@ "text": "Enabled", "color": "gray" }, - "color": "#967ADC", - "notes": "", "options": { "type": "data", "repository": false, "enabled": true - } + }, + "color": "#967ADC", + "notes": "" + }, + { + "id": "1717441414646", + "component": "code", + "tab": "1611921777196", + "name": "device-status", + "x": 588.0833282470703, + "y": 177, + "connections": { + "0": [ + { + "index": "0", + "id": "1717442627834" + }, + { + "index": "0", + "id": "1717442631338" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "", + "color": "gray" + }, + "options": { + "keepmessage": true, + "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n}", + "outputs": 1 + }, + "color": "#656D78", + "notes": "" + }, + { + "id": "1717442627834", + "component": "debug", + "tab": "1611921777196", + "name": "modbus service", + "x": 802.0833282470703, + "y": 139, + "connections": {}, + "disabledio": { + "input": [ + 0 + ], + "output": [] + }, + "state": { + "text": "Enabled", + "color": "gray" + }, + "options": { + "type": "data", + "repository": false, + "enabled": true + }, + "color": "#967ADC", + "notes": "" + }, + { + "id": "1717442631338", + "component": "virtualwireout", + "tab": "1611921777196", + "name": "send-to-services", + "x": 801.0833282470703, + "y": 236, + "connections": {}, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "send-to-services", + "color": "gray" + }, + "options": { + "wirename": "send-to-services" + }, + "color": "#303E4D", + "notes": "" + }, + { + "id": "1718016045116", + "component": "virtualwirein", + "tab": "1612772287426", + "name": "tb-push", + "x": 84.75, + "y": 1300, + "connections": { + "0": [ + { + "index": "0", + "id": "1718016052341" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "tb-push", + "color": "gray" + }, + "options": { + "wirename": "tb-push" + }, + "color": "#303E4D", + "notes": "" + }, + { + "id": "1718016052341", + "component": "slack_filter", + "tab": "1612772287426", + "name": "Slack Filter", + "x": 278, + "y": 1297, + "connections": { + "0": [ + { + "index": "0", + "id": "1718016086212" + }, + { + "index": "0", + "id": "1718016073501" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "Running", + "color": "gray" + }, + "options": { + "slack_channel": "C071KN2Q8SK", + "tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]", + "message_includes": "[\"is responding again\", \"Lamps have turned\", \"Flow has been restarted\"]", + "types": "[\"emergency\", \"critical\", \"error\", \"alert\"]", + "name": "RVO16 Senica - 10.0.0.131" + }, + "color": "#30E193", + "notes": "" + }, + { + "id": "1718016073501", + "component": "httprequest", + "tab": "1612772287426", + "name": "http://192.168.252.2:8004/slack", + "x": 471, + "y": 1354, + "connections": { + "0": [ + { + "index": "0", + "id": "1718016086212" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "", + "color": "gray" + }, + "options": { + "stringify": "json", + "method": "POST", + "url": "http://192.168.252.2:8004/slack" + }, + "color": "#5D9CEC", + "notes": "" + }, + { + "id": "1718016086212", + "component": "debug", + "tab": "1612772287426", + "name": "Debug", + "x": 808, + "y": 1302, + "connections": {}, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "Enabled", + "color": "gray" + }, + "options": { + "type": "data", + "repository": false, + "enabled": true + }, + "color": "#967ADC", + "notes": "" + }, + { + "id": "1718016094070", + "component": "trigger", + "tab": "1612772287426", + "name": "Trigger", + "x": 73, + "y": 1388, + "connections": { + "0": [ + { + "index": "0", + "id": "1718016052341" + } + ] + }, + "disabledio": { + "input": [], + "output": [] + }, + "state": { + "text": "", + "color": "gray" + }, + "options": { + "datatype": "object", + "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }" + }, + "color": "#F6BB42", + "notes": "" } ], - "version": 618 + "version": 615 } \ No newline at end of file diff --git a/flow/dido_controller.js b/flow/dido_controller.js index 0952350..b429b14 100644 --- a/flow/dido_controller.js +++ b/flow/dido_controller.js @@ -11,11 +11,11 @@ exports.icon = 'bolt'; exports.options = { edge: "undefined" }; exports.html = `
-
-
-
Edge TB Name
-
-
+
+
+
Edge TB Name
+
+
`; exports.readme = `# Sets RS232 port and all digital pins on device. Then it starts to receive data from sensors. @@ -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 = "2024-05-10";//rok-mesiac-den +FLOW.OMS_edge_fw_version = "2024-07-08";//rok-mesiac-den FLOW.OMS_edgeName = ""; FLOW.OMS_maintenance_mode = false; @@ -78,7 +78,7 @@ FLOW.OMS_temperature_adress = "";//cmd_manager let alarmStatus = "OFF"; -const instanceSendTo = { +const SEND_TO = { debug: 0, tb: 1, cmd_manager: 2 @@ -152,7 +152,7 @@ exports.install = function(instance) { /* let conversionTable = { "1": {tbname: "", type: "state_of_main_switch", "line": 0}, //state_of_main_switch pin1 - "2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2 + "2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2 "3": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha auto = pin3 "4": {tbname: "", type: "power_supply", "line": 0}, "5": {tbname: "", type: "battery", "line": 0}, @@ -192,7 +192,7 @@ exports.install = function(instance) { /* dbRelays.on('change', function(doc, old) { console.log("'DI_DO_Controller - dbRelays.on('change'"); - instance.send(instanceSendTo.cmd_manager, "reload_relays"); + instance.send(SEND_TO.cmd_manager, "reload_relays"); }); */ @@ -264,14 +264,13 @@ exports.install = function(instance) { { errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line); - //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", instanceSendTo.tb, instance, null ); - sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", instanceSendTo.tb, instance ); + //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null ); + sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance ); } } if(pinsData[key].type == "state_of_contactor") { - let pin = key - 1; if(controller_type === "unipi") pin = key; @@ -298,37 +297,19 @@ exports.install = function(instance) { } ] } - - instance.send(instanceSendTo.tb, dataToTb); + + instance.send(SEND_TO.tb, dataToTb); let time = 3*1000; setTimeout(function(){ - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"}); - sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", instanceSendTo.tb, instance ); + sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", SEND_TO.tb, instance ); monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version); }, time); } - - // TODO: FIND BETTER SOLUTION, THAN REBUILDING TASKS - // we ensure, all tasks will be rebuild twice a week on tuesday or saturday at 11. To set correct switch off and on times - let sendRebuildTasksAt11 = null; - const checkIf11Oclock = () => - { - const d = new Date(); - const h = d.getHours(); - const day = d.getDay(); - - if((day === 2 || day === 6) && h === 11) - { - instance.send(instanceSendTo.cmd_manager, {sender:"dido_controller", cmd:"buildTasks"}); - monitor.info("Task rebuilt at 11 o'clock, tuesday, saturday"); - } - } - sendRebuildTasksAt11 = setInterval(checkIf11Oclock, 3600000); - function handleRsPort() { @@ -339,14 +320,14 @@ exports.install = function(instance) { rsPort.on('error', function(err) { logger.debug("rsPort opened error - failed", err.message); - instance.send(instanceSendTo.debug, err.message); + instance.send(SEND_TO.debug, err.message); errorHandler.sendMessageToService( exports.title + " rsPort opened error - failed: " + err.message); }) rsPort.on('open', async function() { - await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) { + await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) { //set port rsPort.write(Buffer.from(setRSPortData), function(err) { @@ -361,7 +342,7 @@ exports.install = function(instance) { }) }).catch(function (reason) { - //instance.send(instanceSendTo.debug, exports.title + " runSyncExec - promise rejected:" + reason); + //instance.send(SEND_TO.debug, exports.title + " runSyncExec - promise rejected:" + reason); errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason); errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason); @@ -490,7 +471,7 @@ exports.install = function(instance) { deviceStatuses["temperature"] = "OK"; previousValues["temperature"] = value; - instance.send(instanceSendTo.tb, dataToTb); + instance.send(SEND_TO.tb, dataToTb); } return; } @@ -508,7 +489,7 @@ exports.install = function(instance) { ws.on('error', (err) => { monitor.info('websocket error, reconnect') - instance.send(instanceSendTo.debug, err.message); + instance.send(SEND_TO.debug, err.message); clearInterval(startRequests); ws = null; setTimeout(handleWebSocket, 1000); @@ -657,14 +638,14 @@ exports.install = function(instance) { //console.log(values); - instance.send(instanceSendTo.tb, dataToTb); + instance.send(SEND_TO.tb, dataToTb); } function turnOnLine(line, pin, force, info) { - instance.send(instanceSendTo.debug, "turn on line " + line ); + instance.send(SEND_TO.debug, "turn on line " + line ); if(force == undefined) force = false; if(line == 0) @@ -698,7 +679,7 @@ exports.install = function(instance) { { if(relaysData[line].contactor == 1) { - instance.send(instanceSendTo.debug, "line is already on " + line ); + instance.send(SEND_TO.debug, "line is already on " + line ); logger.debug("turnOnLine: line is already on: ", line); return; @@ -775,7 +756,7 @@ exports.install = function(instance) { { if(relaysData[line].contactor == 0) { - instance.send(instanceSendTo.debug, "line is already off " + line ); + instance.send(SEND_TO.debug, "line is already off " + line ); logger.debug("turnOffLine: line already off:", line); return; @@ -828,7 +809,7 @@ exports.install = function(instance) { if(!flowdata.data instanceof Object) return; // console.log('***********************', flowdata.data) - instance.send(instanceSendTo.debug, flowdata.data); + instance.send(SEND_TO.debug, flowdata.data); // we handle nok status from modbus_reader component and thermometer if(flowdata.data?.status) @@ -846,33 +827,34 @@ exports.install = function(instance) { { deviceStatuses["temperature"] = "NOK"; } - return; } + else if(flowdata.data?.values) + { + const values = flowdata.data.values; + if(values.hasOwnProperty("twilight_sensor")) + { + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"]}); + deviceStatuses["twilight_sensor"] = "OK" + } + 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"; + } + else + { + 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" + const updateStatus = checkFinalRVOStatus(); + if(updateStatus) values.status = "OK"; + + sendTelemetry(values, FLOW.OMS_rvo_tbname); } - 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"; - } - else - { - return; - } - - const updateStatus = checkFinalRVOStatus(); - if(updateStatus) values.status = "OK"; - - sendTelemetry(values, FLOW.OMS_rvo_tbname); }) @@ -902,7 +884,7 @@ exports.install = function(instance) { rsPort.write(Buffer.from(obj), function(err) { switchLogic(obj); - instance.send(instanceSendTo.debug, {"WRITE":obj} ); + instance.send(SEND_TO.debug, {"WRITE":obj} ); }); } }) @@ -1195,14 +1177,14 @@ exports.install = function(instance) { { if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) { - sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); + sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch"); values["status"] = "NOK"; deviceStatuses["state_of_main_switch"] = "Off"; } else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) { - sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", instanceSendTo.tb, instance , "state_of_main_switch"); + sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch"); deviceStatuses["state_of_main_switch"] = "On"; } @@ -1247,7 +1229,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: "dido_controller", cmd: "rotary_switch_state", value: value}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value}); //console.log("rotary_switch_state pin", pin2, pin3, value); } @@ -1256,16 +1238,16 @@ exports.install = function(instance) { { if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", instanceSendTo.tb, instance, "power_supply"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance); + sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply"); values["status"] = "NOK"; deviceStatuses["power_supply"] = "NOK"; } else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", instanceSendTo.tb, instance, "power_supply"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance); + sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply"); deviceStatuses["power_supply"] = "OK"; } @@ -1275,16 +1257,16 @@ exports.install = function(instance) { { if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", instanceSendTo.tb, instance, "battery_level"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance); + sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level"); values["status"] = "NOK"; deviceStatuses["battery"] = "NOK"; } else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", instanceSendTo.tb, instance, "battery_level"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance); + sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level"); deviceStatuses["battery"] = "OK"; } @@ -1298,19 +1280,19 @@ exports.install = function(instance) { if (newPinValue != previousValues[pinIndex]) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", instanceSendTo.tb, instance, "rvo_door"); - //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", instanceSendTo.tb, instance, "rvo_door"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", SEND_TO.tb, instance, "rvo_door"); + //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", SEND_TO.tb, instance, "rvo_door"); } if (value === "open" && FLOW.OMS_maintenance_mode) { - sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", instanceSendTo.tb, instance, "rvo_door"); + sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", SEND_TO.tb, instance, "rvo_door"); } if (value === "open" && !FLOW.OMS_maintenance_mode) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", instanceSendTo.tb, instance); - sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", instanceSendTo.tb, instance, "rvo_door"); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance); + sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", SEND_TO.tb, instance, "rvo_door"); values["status"] = "NOK"; //console.log(door_has_been_open_without_permision_alarm_is_on); @@ -1325,7 +1307,7 @@ exports.install = function(instance) { if(alarmStatus == "ON") turnOffAlarm(); //turnOffAlarm(); - sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", instanceSendTo.tb, instance, "rvo_door"); + sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", SEND_TO.tb, instance, "rvo_door"); } deviceStatuses["door_condition"] = value; @@ -1364,12 +1346,12 @@ exports.install = function(instance) { 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 ); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance ); newPinValue = 0; } else if (set.size !== 1 && twilightError) { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", instanceSendTo.tb, instance ); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance ); twilightError = false; twilight_sensor_array.shift(); newPinValue = value; @@ -1387,7 +1369,7 @@ exports.install = function(instance) { 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}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: average}); twilight_sensor = []; @@ -1398,11 +1380,11 @@ exports.install = function(instance) { } else if(type == "state_of_contactor") { - //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", instanceSendTo.tb, instance ); + //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", SEND_TO.tb, instance ); if(!(deviceStatuses["state_of_contactor"][line] == value)) { - sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", instanceSendTo.tb, instance ); + sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance ); } else { @@ -1444,7 +1426,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: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged}); }, time); reportLineStatus(line); @@ -1469,7 +1451,7 @@ exports.install = function(instance) { if(valueChanged) { - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line}); //mame iba 3 istice. vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia (napr linia 1, paralelna s nou je linia 4, key je string "4") // ak je 7 linii, na 1 istici je linia 1,4,7 @@ -1483,7 +1465,7 @@ exports.install = function(instance) { { if(!relaysData.hasOwnProperty(lineOnSameBraker[i])) continue; - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i]}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i]}); deviceStatuses["state_of_breaker"][lineOnSameBraker[i]] = value; reportLineStatus(lineOnSameBraker[i]); @@ -1502,7 +1484,7 @@ exports.install = function(instance) { if(relaysData.hasOwnProperty(lineOnSameBraker)) { - instance.send(instanceSendTo.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3}); + instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3}); deviceStatuses["state_of_breaker"][line + 3] = value; reportLineStatus(line + 3); @@ -1598,7 +1580,7 @@ exports.install = function(instance) { ] } - instance.send(instanceSendTo.tb, dataToTb); + instance.send(SEND_TO.tb, dataToTb); } } diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js index 898816e..f34ec9a 100644 --- a/flow/modbus_reader.js +++ b/flow/modbus_reader.js @@ -14,8 +14,8 @@ exports.readme = ` 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 modbus = require('jsmodbus'); +const SerialPort = require('serialport'); const { timeoutInterval, deviceConfig } = require("../databases/modbus_config"); const { sendNotification } = require('./helper/notification_reporter'); @@ -30,6 +30,8 @@ const SEND_TO = { //to handle NOK and OK sendNotifications s const numberOfNotResponding = {}; let tbName = null; +let mainSocket; + exports.install = function(instance) { @@ -50,6 +52,10 @@ exports.install = function(instance) { this.lengthOfActualDeviceStream = null; this.device = null; + // lampSwitchNotification helper variables + this.onNotificationSent = false; + this.offNotificationSent = false; + this.startSocket(); } @@ -215,6 +221,7 @@ exports.install = function(instance) { }; this.checkNullVoltage(values); + this.lampSwitchNotification(values); instance.send(SEND_TO.dido_controller, {values: values}); @@ -243,32 +250,6 @@ exports.install = function(instance) { } } - - // sendFinalObjects = (values) => - // { - - // const date = Date.now(); - // // values["status"] = "OK"; - - // const dataToTB = { - // [tbName]: [ - // { - // "ts": date, - // "values": values - // } - // ] - // }; - - // instance.send(SEND_TO.tb, dataToTB); - - // const dataToDiDo = { - // values: values - // } - - // instance.send(SEND_TO.dido_controller, dataToDiDo); - // } - - calculateValue = (response, multiplier) => { let value = 0; @@ -296,7 +277,6 @@ exports.install = function(instance) { 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; @@ -313,19 +293,41 @@ exports.install = function(instance) { if(values[singleValue] == 0) { FLOW.OMS_no_voltage.add(phase); - sendNotification("modbus_citys: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase ); + sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase ); // console.log('no voltage') } else { FLOW.OMS_no_voltage.delete(phase); // console.log('voltage detected') - sendNotification("modbus_citys: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase); + sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase); } } }) } + /** + * function sends notification to slack and to tb, if EM total_power value changes more than 500. This should show, that RVO lamps has been switched on or off + */ + lampSwitchNotification = (values) => { + + if(!values.hasOwnProperty("total_power")) return; + + const actualTotalPower = values.total_power; + if(actualTotalPower > 600 && this.onNotificationSent == false) + { + sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_on", {}, "", SEND_TO.tb, instance); + this.onNotificationSent = true; + this.offNotificationSent = false; + } + else if(actualTotalPower <= 600 && this.offNotificationSent == false) + { + sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_off", {}, "", SEND_TO.tb, instance); + this.onNotificationSent = false; + this.offNotificationSent = true; + } + } + } const isObjectEmpty = (objectName) => { @@ -333,8 +335,14 @@ exports.install = function(instance) { } setTimeout(() => { - const newSocket = new SocketWithClients(); + + mainSocket = new SocketWithClients(); tbName = FLOW.OMS_rvo_tbname; + + // this notification is to show, that flow (unipi) has been restarted + sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance); + }, 25000); + } diff --git a/flow/slack_filter.js b/flow/slack_filter.js new file mode 100644 index 0000000..a27c9e1 --- /dev/null +++ b/flow/slack_filter.js @@ -0,0 +1,187 @@ +exports.id = 'slack_filter'; +exports.title = 'Slack Filter'; +exports.group = 'Citysys'; +exports.color = '#30E193'; +exports.input = 1; +exports.output = 1; +exports.author = 'Jakub Klena'; +exports.icon = 'plug'; +exports.version = '1.0.8'; +exports.options = { 'name':'', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes':'["is responding again"]', 'tag_on_include':'[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel':'' }; + +exports.html = `
+
+
+
@(Name of this server)
+
+
+
@(Slack channel to receive the alerts)
+
+
+
@(Watch these types, comma separated names)
+
+
+
@(Watch messages that include any of the following strings)
+
+
+
@(Tag people if message includes something)
+
+
+
`; + +exports.readme = `# Slack Filter`; + +exports.install = function(instance) { + var running = false; + instance["savedSlackMessages"] = []; + var timer = null; + + instance.on('data', function(response) { + if (!running) return; + let value = response.data; + if (typeof value !== 'object') return; + + let can = false + var k = Object.keys(value); + var interested = JSON.parse(instance.options.types); + var msg_incl = JSON.parse(instance.options.message_includes); + var tags = JSON.parse(instance.options.tag_on_include); + + if (k.length <= 0) return; + if (value[k[0]].length <= 0) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0], 'values')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values'], '_event')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'type')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'source')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event']['source'], 'func')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'message')) return; + if (!Object.prototype.hasOwnProperty.call(value[k[0]][0]['values']['_event'], 'message_data')) return; + + let icon = ':totaljs:'; + let type = value[k[0]][0]['values']['_event']['type']; + let source = value[k[0]][0]['values']['_event']['source']['func']; + let message = value[k[0]][0]['values']['_event']['message']; + let message_data = value[k[0]][0]['values']['_event']['message_data']; + let tag = ''; + + switch(type){ + case 'debug': + icon = ':beetle:'; + break; + case 'info': + icon = ':speech_balloon:'; + break; + case 'notice': + icon = ':speech_balloon:'; + break; + case 'warning': + icon = ':exclamation:'; + break; + case 'alert': + icon = ':warning:'; + break; + case 'error': + icon = ':no_entry:'; + break; + case 'emergency': + icon = ':fire:'; + break; + case 'critical': + icon = ':fire:'; + break; + } + + // Check if this message includes one of the strings we are watching for + for (const msg of msg_incl){ + if (message.includes(msg)){ + if (msg == 'is responding again') icon = ':large_green_circle:'; + can = true; + break; + } + } + // Check if message is one of the types we are watching for + if (interested.includes(type)){ + can = true; + } + + if (!can) return; + + + // Check for each person tags based on what the message includes + for (const person of tags){ + for (const msg of person.includes){ + if (message.includes(msg)){ + tag += '<@'+person.user_id+'> '; + break; // Break out from this person checks as they are already tagged now + } + } + } + // Now that all people are tagged add new line symbol + if (tag != '') tag += '\n'; + + let send_data = tag+instance.options.name+' '+type.toUpperCase()+'\n*Source*: '+source+'\n*Message*: '+message; + if (message_data) { + send_data += '\nData: '+message_data; + } + + let ignore_msg = false + if (message.includes('Configuration of dimming profile to node no')){ + for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){ + if (FLOW["savedSlackMessages"][i].message == message){ + ignore_msg = true; + break; + } + } + if (!ignore_msg){ + FLOW["savedSlackMessages"].push({message, 'dateandtime': Date.now()}); + if (timer === null){ + timer = setTimeout(checkSavedMessages, 60*60000); + } + } + } + + if (!ignore_msg){ + instance.send2({'msg':send_data,'bot_name':instance.options.name+' '+type.toUpperCase(),'bot_icon':icon,'channel':instance.options.slack_channel}); + } + }); + + function checkSavedMessages(){ + var d = Date.now(); + d = d - 86400000; // older then 24hr + var a = []; + //Remove msgs older then 24hr + for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){ + if (FLOW["savedSlackMessages"][i].dateandtime > d){ + a.push(FLOW["savedSlackMessages"][i]); + } + } + FLOW["savedSlackMessages"] = a; + + if (FLOW["savedSlackMessages"].length > 0) { + timer = setTimeout(checkSavedMessages, 60*60000); + } else { + timer = null; + } + } + + instance.reconfigure = function() { + try { + if (!FLOW["savedSlackMessages"]){ + FLOW["savedSlackMessages"] = []; + } + + if (instance.options.name) { + instance.status('Running'); + running = true; + } else { + instance.status('Please enter name', 'red'); + running = false; + } + } catch (e) { + instance.error('Citysys connector: ' + e.message); + } + }; + + instance.on('options', instance.reconfigure); + instance.reconfigure(); +}; \ No newline at end of file From 7e20c7d3f0210647ccd9e53627aba1c2d0044b51 Mon Sep 17 00:00:00 2001 From: Jakub Klena Date: Mon, 9 Sep 2024 13:44:39 +0200 Subject: [PATCH 9/9] Removing duplicate --- flow/gettemperature.js | 218 ----------------------------------------- 1 file changed, 218 deletions(-) delete mode 100644 flow/gettemperature.js diff --git a/flow/gettemperature.js b/flow/gettemperature.js deleted file mode 100644 index 720592a..0000000 --- a/flow/gettemperature.js +++ /dev/null @@ -1,218 +0,0 @@ -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 } = 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(); - }, 3000); - - startRead = setInterval(start, timeoutMin * 1000 * 60); -}; \ No newline at end of file