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 = `
-
-`;
-
-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 = `
+
+`;
+
+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 = `
`;
-
-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
-
-
-
-
-
-
@(Client id)
-
@(Supports variables, example: \`client_{device-id}\`)
-
@(Secure (ssl))
-
-
-
-
-
-
@(Require Authorization)
-
-
-
-
-
-
-
-
@(Last will topic)
-
@(Supports variables, example: \`lwt/{device-id}\`)
-
-
-
@(Last will message)
-
@(Supports variables, example: \`{device-id} is offline\`)
-
-
-
-`;
-
-exports.readme = `
-# MQTT Broker
-
-## Input
-Allows to change connection programaticaly
-\`\`\`javascipt
-{
- host: '1.2.3.4',
- port: '',
- secure: true/false,
- username: 'john',
- password: 'X',
- lwttopic: '',
- lwtmessage: '',
- clientid: ''
-}
-\`\`\`
-`;
-
-var MQTT_BROKERS = [];
-var mqtt;
-
-global.MQTT = {};
-
-exports.install = function(instance) {
-
- var broker;
-
- mqtt = require('mqtt');
-
- instance.on('data', function(flowdata){
- var data= flowdata.data;
- var options = instance.options;
-
- if (data.host && data.port)
- return instance.custom.reconfigure(data, options);
-
- if (data.close === true)
- instance.close(NOOP);
- });
-
- instance.custom.reconfigure = function(o, old_options) {
-
- if (old_options)
- MQTT_BROKERS = MQTT_BROKERS.remove(function(b){
- return b.id === old_options.id;
- });
-
- var options = instance.options;
-
- if (!options.host || !options.port) {
- instance.status('Not configured', 'red');
- return;
- }
-
- options.id = (options.username || '') + '@' + options.host + ':' + options.port;
-
- if (broker) {
- broker.close();
- EMIT('mqtt.brokers.status', 'reconfigured', old_options.id, options.id);
- }
-
- instance.custom.createBroker();
- };
-
- instance.custom.createBroker = function() {
-
- ON('mqtt.brokers.status', brokerstatus);
-
- var o = instance.options;
- var opts = {
- host: o.host,
- port: o.port,
- id: o.id,
- secure: o.secure,
- rejectUnauthorized: false,
- reconnectPeriod: 3000,
- resubscribe: false
- };
-
- if (o.auth) {
- opts.username = o.username;
- opts.password = o.password;
- }
-
- if (o.lwt) {
- opts.will = {
- topic: instance.arg(o.lwttopic),
- payload: instance.arg(o.lwtmessage)
- }
- }
-
- if (o.clientid)
- opts.clientId = instance.arg(o.clientid);
-
- broker = new Broker(opts);
- MQTT_BROKERS.push(broker);
-
- instance.status('Ready');
- };
-
- instance.close = function(done) {
-
- broker && broker.close(function() {
- MQTT_BROKERS = MQTT_BROKERS.remove('id', instance.options.id);
- EMIT('mqtt.brokers.status', 'removed', instance.options.id);
- });
-
- OFF('mqtt.brokers.status', brokerstatus);
-
- done();
- };
-
- function brokerstatus(status, brokerid, err) {
- if (brokerid !== instance.options.id)
- return;
-
- switch (status) {
- case 'connecting':
- instance.status('Connecting', '#a6c3ff');
- break;
- case 'connected':
- instance.status('Connected', 'green');
- break;
- case 'disconnected':
- instance.status('Disconnected', 'red');
- break;
- case 'connectionfailed':
- instance.status('Connection failed', 'red');
- break;
- case 'error':
- instance.error('MQTT Error, ID: ' + instance.id + '\n ' + err);
- break;
- }
- }
-
- instance.on('options', instance.custom.reconfigure);
- instance.custom.reconfigure();
-};
-
-FLOW.trigger('mqtt.brokers', function(next) {
- var brokers = [''];
- MQTT_BROKERS.forEach(n => brokers.push(n.id));
- next(brokers);
-});
-
-MQTT.add = function(brokerid, componentid) {
- var broker = MQTT_BROKERS.findItem('id', brokerid);
-
- if (broker)
- broker.add(componentid);
-};
-
-MQTT.remove = function(brokerid, componentid) {
- var broker = MQTT_BROKERS.findItem('id', brokerid);
- broker && broker.remove(componentid);
-};
-
-MQTT.publish = function(brokerid, topic, data, options) {
- var broker = MQTT_BROKERS.findItem('id', brokerid);
- if (broker)
- broker.publish(topic, data, options);
- else
- EMIT('mqtt.brokers.status', 'error', brokerid, 'No such broker');
-};
-
-MQTT.subscribe = function(brokerid, componentid, topic, qos) {
- var broker = MQTT_BROKERS.findItem('id', brokerid);
-
- if (!broker)
- return;
-
- broker.add(componentid);
- broker.subscribe(componentid, topic, qos);
-};
-
-MQTT.unsubscribe = function(brokerid, componentid, topic, qos) {
- var broker = MQTT_BROKERS.findItem('id', brokerid);
- if (!broker)
- return;
-
- broker.unsubscribe(componentid, topic);
- broker.remove(componentid);
-};
-
-MQTT.broker = function(brokerid) {
- return MQTT_BROKERS.findItem('id', brokerid);
-};
-
-/*
-
- https://github.com/mqttjs/MQTT.js/blob/master/examples/client/secure-client.js
-
-*/
-
-/*
- TODO
-
- - add `birth` and `last will and testament` messages
- - add options to self.client.connect(broker [,options]); - credentials, certificate etc.
-
-
-*/
-
-function Broker(options) {
- var self = this;
-
- if (!options.host || !options.port)
- return false;
-
- self.connecting = false;
- self.connected = false;
- self.closing = false;
- self.components = [];
- self.subscribtions = {};
- self.id = options.id;
- self.options = options;
- setTimeout(function() {
- EMIT('mqtt.brokers.status', 'new', self.id);
- }, 500);
- return self;
-}
-
-Broker.prototype.connect = function() {
-
- var self = this;
- if (self.connected || self.connecting)
- return EMIT('mqtt.brokers.status', self.connected ? 'connected' : 'connecting', self.id);
-
- self.connecting = true;
- var broker = self.options.secure ? 'mqtts://' : 'mqtt://' + self.options.host + ':' + self.options.port;
-
- EMIT('mqtt.brokers.status', 'connecting', self.id);
-
- self.client = mqtt.connect(broker, self.options);
-
- self.client.on('connect', function() {
- self.connecting = false;
- self.connected = true;
- if (self.reconnecting) {
- EMIT('mqtt.brokers.status', 'reconnected', self.id);
- self.reconnecting = false;
- self.resubscribe();
- }
- EMIT('mqtt.brokers.status', 'connected', self.id);
- });
-
- self.client.on('reconnect', function() {
- self.connecting = true;
- self.connected = false;
- self.reconnecting = true;
- EMIT('mqtt.brokers.status', 'connecting', self.id);
- });
-
- self.client.on('message', function(topic, message) {
- message = message.toString();
- if (message[0] === '{') {
- TRY(function() {
- message = JSON.parse(message);
- }, () => FLOW.debug('MQTT: Error parsing data', message));
- }
- EMIT('mqtt.brokers.message', self.id, topic, message);
- });
-
- self.client.on('close', function(err) {
- if (err && err.toString().indexOf('Error')) {
- self.connecting = false;
- self.connected = false;
- EMIT('mqtt.brokers.status', 'error', self.id, err.code);
- }
-
- if (self.connected || !self.connecting) {
- self.connected = false;
- EMIT('mqtt.brokers.status', 'disconnected', self.id);
- } else if (self.connecting) {
- self.connecting = false;
- EMIT('mqtt.brokers.status', 'connectionfailed', self.id);
- }
- });
-
- self.client.on('error', function(err) {
-
- if (self.connecting) {
- self.client.end();
- self.connecting = false;
- EMIT('mqtt.brokers.status', 'error', self.id, err);
- }
- });
-
-};
-
-Broker.prototype.disconnect = function(reconnect) {
- var self = this;
- if (!self.closing)
- self.close(function(){
- reconnect && self.connect();
- });
-};
-
-Broker.prototype.close = function(callback) {
- var self = this;
- self.closing = true;
-
- if ((self.connected || self.connecting) && self.client && self.client.end)
- self.client.end(true, cb);
- else
- cb();
-
- function cb() {
- EMIT('mqtt.brokers.status', 'disconnected', self.id);
- self.client && self.client.removeAllListeners();
- self.components = [];
- self.client = null;
- callback && callback();
- }
-};
-
-Broker.prototype.subscribe = function(componentid, topic) {
- var self = this;
- self.subscribtions[topic] = self.subscribtions[topic] || [];
- if (self.subscribtions[topic].indexOf(componentid) > -1)
- return;
- self.client.subscribe(topic);
- self.subscribtions[topic].push(componentid);
-};
-
-Broker.prototype.resubscribe = function() {
- var self = this;
- var topics = Object.keys(self.subscribtions);
- for (var i = 0; i < topics.length; i++)
- self.client.subscribe(topics[i]);
-};
-
-Broker.prototype.unsubscribe = function(componentid, topic) {
- var self = this;
- var sub = self.subscribtions[topic];
- if (sub) {
- self.subscribtions[topic] = sub.remove(componentid);
- self.client.connected && !self.subscribtions[topic].length && self.client.unsubscribe(topic);
- }
-};
-
-Broker.prototype.publish = function(topic, data, options) {
- var self = this;
- if (!self.connected)
- return;
-
- if (typeof(data) === 'object') {
- options.qos = parseInt(data.qos || options.qos);
- options.retain = data.retain || options.retain;
- topic = data.topic || topic;
- data.payload && (data = typeof(data.payload) === 'string' ? data.payload : JSON.stringify(data.payload));
- }
-
- if (options.qos !== 0 || options.qos !== 1 || options.qos !== 2)
- options.qos = null;
-
- if (typeof(data) !== 'string')
- data = JSON.stringify(data);
-
- self.client.publish(topic, data || '', options);
-};
-
-Broker.prototype.add = function(componentid) {
- var self = this;
- self.components.indexOf(componentid) === -1 && self.components.push(componentid);
- self.connect();
-};
-
-Broker.prototype.remove = function(componentid) {
- var self = this;
- self.components = self.components.remove(componentid);
- !self.components.length && self.disconnect();
-};
diff --git a/flow/mqtt_listener.js b/flow/mqtt_listener.js
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
-
-
-
-
-
`;
-
-
-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 = ``;
-
-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
- }
- ]
- }]
- }
-}