diff --git a/addSwitch.py b/addSwitch.py
deleted file mode 100644
index e58f7f4..0000000
--- a/addSwitch.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import os
-
-def process_set_file():
- """
- Checks if /root/flowserver exists, reads set.txt, and modifies the second line.
- """
- default_folder = "/root/flowserver" if os.path.exists("/root/flowserver") else "/home/unipi/flowserver"
- flag = 1 if default_folder == "/root/flowserver" else 0
-
- try:
- with open("/home/unipi/flowserver/databases/settings.table", "r") as f:
- lines = f.readlines()
-
- if len(lines) >= 2:
- lines[0] = lines[0].rstrip('\n') + "|has_main_switch:boolean\n"
- second_line = lines[1].strip() # remove trailing newline
- last_pipe_index = second_line.rfind("|")
-
- if last_pipe_index != -1:
- modified_line = second_line[:last_pipe_index + 1] + str(flag) + "|" + second_line[last_pipe_index + 1:]
- lines[1] = modified_line
- else:
- print("Warning: No '|' character found in the second line of set.txt")
-
- with open("/home/unipi/flowserver/databases/settings.table", "w") as f:
- f.writelines(lines)
- else:
- print("Warning: settings.table has less than two lines.")
-
- except FileNotFoundError:
- print("Error: settings.table not found.")
- except Exception as e:
- print(e)
-
-# if __name__ == "__main__":
-process_set_file()
diff --git a/cloud_topic.py b/cloud_topic.py
deleted file mode 100644
index 77c31f1..0000000
--- a/cloud_topic.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# import os
-#
-# def modify_file(file_path):
-# """
-# Modifies the given file by:
-# 1. Appending "|cloud_topic" to the first line.
-# 2. Inserting the text from the third "." to the first "|" on the second line after the last "|" character.
-#
-# Args:
-# file_path (str): The path to the file to be modified.
-# """
-#
-# with open(file_path, 'r+') as f:
-# lines = f.readlines()
-#
-# # Modify the first line
-# lines[0] += "|cloud_topic:string"
-#
-# # Modify the second line
-# second_line = lines[1].strip() # Remove leading/trailing whitespace
-# first_pipe_index = second_line.find('|')
-# third_dot_index = second_line.find('.', second_line.find('.', second_line.find('.') + 1) + 1)
-# text_to_insert = second_line[third_dot_index:first_pipe_index]
-#
-# last_pipe_index = second_line.rfind('|')
-# lines[1] = second_line[:last_pipe_index + 1] + text_to_insert + "|" + second_line[last_pipe_index + 1:]
-#
-# print(first_pipe_index, third_dot_index, text_to_insert, last_pipe_index)
-# # Write the modified lines back to the file
-# # f.seek(0)
-# # f.writelines(lines)
-# # f.truncate()
-#
-# # Example usage:
-# file_path = "settings.table" # Replace with the actual file path
-# modify_file(file_path)
-#
-
-
-def modify_file(file_path):
- """
- Modifies the given file by:
- 1. Appending "|cloud_topic" to the first line.
- 2. Inserting the text between the third "." and the second "|" on the second line after the last "|" character.
-
- Args:
- file_path (str): The path to the file to be modified.
- """
-
- with open(file_path, 'r+') as f:
- lines = f.readlines()
-
- first_line = lines[0].strip()
- first_line += "|cloud_topic:string\n"
- # Modify the first line
- lines[0] = first_line
-
- # Modify the second line
- second_line = lines[1].strip() # Remove leading/trailing whitespace
- first_pipe_index = second_line.find('|')
- second_pipe_index = second_line.find('|', first_pipe_index + 1)
- third_dot_index = second_line.find('.', second_line.find('.', second_line.find('.') + 1) + 1)
- text_to_insert = "u" + second_line[third_dot_index+1:second_pipe_index]
-
- last_pipe_index = second_line.rfind('|')
- lines[1] = second_line[:last_pipe_index + 1] + text_to_insert + "|" + second_line[last_pipe_index + 1:]
-
- print(first_pipe_index, third_dot_index, text_to_insert, last_pipe_index)
- # Write the modified lines back to the file
- f.seek(0)
- f.writelines(lines)
- f.truncate()
-
-# Example usage:
-file_path = "/home/unipi/flowserver/databases/settings.table" # Replace with the actual file path
-modify_file(file_path)
diff --git a/config b/config
index 9472cb0..b10cd71 100644
--- a/config
+++ b/config
@@ -6,7 +6,7 @@ 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|time_of_last_communication:number
-table.settings : rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string|has_main_switch:boolean
+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:string|type:string|line:number
table.notifications : key:string|weight:string|sk:string|en:string
diff --git a/createNode.py b/createNode.py
deleted file mode 100644
index 21406cc..0000000
--- a/createNode.py
+++ /dev/null
@@ -1,43 +0,0 @@
-print("zaciname")
-import re, json
-
-search_str = '|'
-final = []
-counter = 1
-with open("/home/unipi/flowserver/databases/nodes.table", 'r') as file:
-# with open("/home/rasta5man/dev/oms/flowserver/databases/nodes.table", 'r') as file:
- # Read each line in the file
- for line in file:
- # Print each line
- line = line.strip()
- print(line)
- if counter != 1:
- i = [m.start() for m in re.finditer(re.escape(search_str), line)]
- node = line[ i[0] + 1 : i[1] ]
- tbname = line[ i[1] + 1 : i[2] ]
- final.append({node:tbname})
- counter += 1
-print(json.dumps(final))
-f = open("/home/unipi/flowserver/databases/nodes_original/nodes_original.table", "w")
-f.write(json.dumps(final))
-f.close()
-
-
-#
-# # ``d`` has to be replaced with a different character
-# old_character = "'"
-#
-# # ``t`` will replace ``d`
-# new_character = '"'
-# resultant_string = 0;
-# with open("/home/unipi/flowserver/databases/nodes_original/nodes_original.table", 'r') as file:
-# for line in file:
-# resultant_string = re.sub("'", '"', line)
-#
-# resultant_string = re.sub(" ", "", resultant_string)
-# print(resultant_string)
-#
-# f = open("/home/unipi/flowserver/databases/nodes_original/nodes_original.table", "w")
-# f.write(str(resultant_string))
-# f.close()
-#
diff --git a/databases/accelerometer_db.js b/databases/accelerometer_db.js
deleted file mode 100644
index fdfc7fd..0000000
--- a/databases/accelerometer_db.js
+++ /dev/null
@@ -1,3055 +0,0 @@
-let naklony = {
- "3993": { "label": "1/3A", "naklon": 0 },
- "3989": { "label": "1/3B", "naklon": 15 },
- "3976": { "label": "1/1", "naklon": 0 },
- "4181": { "label": "1/2", "naklon": 0 },
- "4376": { "label": "1/4", "naklon": 15 },
- "3868": { "label": "1/5", "naklon": 15 },
- "3728": { "label": "1/6", "naklon": 15 },
- "3730": { "label": "1/7", "naklon": 0 },
- "4374": { "label": "1/8", "naklon": 0 },
- "3718": { "label": "1/9", "naklon": 15 },
- "4375": { "label": "1/10", "naklon": 15 },
- "4172": { "label": "1/11", "naklon": 15 },
- "4176": { "label": "1/12", "naklon": 15 },
- "3800": { "label": "2/1", "naklon": 5 },
- "3823": { "label": "2/2", "naklon": 5 },
- "3905": { "label": "2/3", "naklon": 5 },
- "3803": { "label": "2/4", "naklon": 5 },
- "3817": { "label": "2/5", "naklon": 5 },
- "3818": { "label": "2/6", "naklon": 5 },
- "3811": { "label": "2/7", "naklon": 5 },
- "3915": { "label": "2/8", "naklon": 5 },
- "3843": { "label": "2/9", "naklon": 10 },
- "3827": { "label": "2/10", "naklon": 10 },
- "4220": { "label": "2/11", "naklon": 10 },
- "3826": { "label": "2/12", "naklon": 10 },
- "3834": { "label": "2/13", "naklon": 10 },
- "3838": { "label": "2/14", "naklon": 10 },
- "2823": { "label": "2/15", "naklon": 10 },
- "3750": { "label": "2/16", "naklon": 10 },
- "3378": { "label": "2/17", "naklon": 0 },
- "3376": { "label": "2/18", "naklon": 0 },
- "3379": { "label": "2/19", "naklon": 0 },
- "3285": { "label": "2/20", "naklon": 0 },
- "3382": { "label": "2/21", "naklon": 0 },
- "3383": { "label": "2/22", "naklon": 0 },
- "3375": { "label": "2/24", "naklon": 0 },
- "3381": { "label": "2/25", "naklon": 0 },
- "3380": { "label": "2/26", "naklon": 0 },
- "3828": { "label": "2/27", "naklon": 10 },
- "3377": { "label": "2/28", "naklon": 0 },
- "3591": { "label": "7/1", "naklon": 0 },
- "3587": { "label": "7/2", "naklon": 0 },
- "3468": { "label": "7/3", "naklon": 0 },
- "3466": { "label": "7/4", "naklon": 0 },
- "3474": { "label": "7/5", "naklon": 0 },
- "3481": { "label": "7/6", "naklon": 0 },
- "3589": { "label": "7/7", "naklon": 0 },
- "3472": { "label": "7/8", "naklon": 0 },
- "3473": { "label": "7/9", "naklon": 0 },
- "3584": { "label": "7/10", "naklon": 0 },
- "3571": { "label": "7/11", "naklon": 0 },
- "3476": { "label": "7/12", "naklon": 0 },
- "3590": { "label": "7/13", "naklon": 0 },
- "3478": { "label": "7/14", "naklon": 0 },
- "3471": { "label": "7/15", "naklon": 0 },
- "3467": { "label": "7/16", "naklon": 0 },
- "3479": { "label": "7/17", "naklon": 0 },
- "3480": { "label": "7/18", "naklon": 0 },
- "3477": { "label": "7/19", "naklon": 0 },
- "3362": { "label": "12/1", "naklon": 0 },
- "3355": { "label": "12/2", "naklon": 0 },
- "3356": { "label": "12/3", "naklon": 0 },
- "3349": { "label": "12/4", "naklon": 0 },
- "3357": { "label": "12/5", "naklon": 0 },
- "3350": { "label": "12/6", "naklon": 0 },
- "3353": { "label": "12/7", "naklon": 0 },
- "3539": { "label": "12/8", "naklon": 0 },
- "3050": { "label": "12/9", "naklon": 0 },
- "3361": { "label": "12/10", "naklon": 0 },
- "3360": { "label": "12/11", "naklon": 0 },
- "3358": { "label": "12/12", "naklon": 0 },
- "3541": { "label": "12/13", "naklon": 0 },
- "3551": { "label": "12/14", "naklon": 0 },
- "3514": { "label": "12/15", "naklon": 0 },
- "3547": { "label": "12/16", "naklon": 0 },
- "3562": { "label": "12/17", "naklon": 0 },
- "3525": { "label": "12/18", "naklon": 0 },
- "3558": { "label": "12/19", "naklon": 0 },
- "3511": { "label": "12/20", "naklon": 0 },
- "3058": { "label": "12/21", "naklon": 0 },
- "3062": { "label": "12/22", "naklon": 0 },
- "3070": { "label": "12/23", "naklon": 0 },
- "3447": { "label": "12/24", "naklon": 0 },
- "3056": { "label": "12/25", "naklon": 0 },
- "3057": { "label": "12/26", "naklon": 0 },
- "3071": { "label": "12/27", "naklon": 0 },
- "3061": { "label": "12/28", "naklon": 0 },
- "3069": { "label": "12/29", "naklon": 0 },
- "3077": { "label": "12/30", "naklon": 0 },
- "3080": { "label": "12/31", "naklon": 0 },
- "3081": { "label": "12/32", "naklon": 0 },
- "3078": { "label": "12/33", "naklon": 0 },
- "4037": { "label": "12/34", "naklon": 0 },
- "3067": { "label": "12/35", "naklon": 0 },
- "3051": { "label": "12/36", "naklon": 0 },
- "2924": { "label": "12/37", "naklon": 0 },
- "3060": { "label": "12/38", "naklon": 0 },
- "3073": { "label": "12/39", "naklon": 0 },
- "3469": { "label": "12/40", "naklon": 0 },
- "2923": { "label": "12/41", "naklon": 0 },
- "2925": { "label": "12/42", "naklon": 0 },
- "3359": { "label": "12/43", "naklon": 0 },
- "3055": { "label": "12/44", "naklon": 0 },
- "2922": { "label": "12/45", "naklon": 0 },
- "3084": { "label": "12/46", "naklon": 0 },
- "3064": { "label": "12/47", "naklon": 0 },
- "3066": { "label": "12/48", "naklon": 0 },
- "3072": { "label": "12/49", "naklon": 0 },
- "3415": { "label": "13/13A", "naklon": 0 },
- "3409": { "label": "13/13B", "naklon": 0 },
- "3399": { "label": "13/13C", "naklon": 0 },
- "3410": { "label": "13/29A", "naklon": 0 },
- "3407": { "label": "13/29B", "naklon": 0 },
- "3405": { "label": "13/34A", "naklon": 0 },
- "3404": { "label": "13/34B", "naklon": 0 },
- "3392": { "label": "13/45A", "naklon": 0 },
- "3386": { "label": "13/45B", "naklon": 0 },
- "3303": { "label": "13/60A", "naklon": 3 },
- "3302": { "label": "13/60B", "naklon": 3 },
- "3319": { "label": "13/70A", "naklon": 6 },
- "3317": { "label": "13/70B", "naklon": 6 },
- "3326": { "label": "13/70C", "naklon": 6 },
- "3351": { "label": "13/73A", "naklon": 6 },
- "3313": { "label": "13/73B", "naklon": 6 },
- "3316": { "label": "13/83A", "naklon": 0 },
- "3320": { "label": "13/83B", "naklon": 0 },
- "3336": { "label": "13/95A", "naklon": 0 },
- "3323": { "label": "13/95B", "naklon": 0 },
- "3339": { "label": "13/98A", "naklon": 0 },
- "3333": { "label": "13/98B", "naklon": 0 },
- "3425": { "label": "13/1", "naklon": 0 },
- "3419": { "label": "13/2", "naklon": 0 },
- "3416": { "label": "13/3", "naklon": 0 },
- "3332": { "label": "13/4", "naklon": 0 },
- "3422": { "label": "13/5", "naklon": 0 },
- "3417": { "label": "13/6", "naklon": 0 },
- "3418": { "label": "13/7", "naklon": 0 },
- "3424": { "label": "13/8", "naklon": 0 },
- "3334": { "label": "13/9", "naklon": 0 },
- "4363": { "label": "13/10", "naklon": 0 },
- "3423": { "label": "13/11", "naklon": 0 },
- "3406": { "label": "13/12", "naklon": 0 },
- "3411": { "label": "13/14", "naklon": 0 },
- "3412": { "label": "13/15", "naklon": 0 },
- "3413": { "label": "13/16", "naklon": 0 },
- "3414": { "label": "13/17", "naklon": 0 },
- "3391": { "label": "13/18", "naklon": 0 },
- "3370": { "label": "13/19", "naklon": 0 },
- "3369": { "label": "13/20", "naklon": 0 },
- "3408": { "label": "13/21", "naklon": 0 },
- "3393": { "label": "13/22", "naklon": 0 },
- "3128": { "label": "13/23", "naklon": 0 },
- "3197": { "label": "13/24", "naklon": 0 },
- "4364": { "label": "13/25", "naklon": 0 },
- "3155": { "label": "13/26", "naklon": 0 },
- "3196": { "label": "13/27", "naklon": 0 },
- "3144": { "label": "13/28", "naklon": 0 },
- "3150": { "label": "13/30", "naklon": 0 },
- "3390": { "label": "13/31", "naklon": 0 },
- "3401": { "label": "13/32", "naklon": 0 },
- "3275": { "label": "13/33", "naklon": 0 },
- "3371": { "label": "13/35", "naklon": 0 },
- "3389": { "label": "13/36", "naklon": 0 },
- "3388": { "label": "13/37", "naklon": 0 },
- "3365": { "label": "13/38", "naklon": 0 },
- "3363": { "label": "13/39", "naklon": 0 },
- "3397": { "label": "13/40", "naklon": 0 },
- "3567": { "label": "13/40/1", "naklon": 0 },
- "3387": { "label": "13/41", "naklon": 0 },
- "3403": { "label": "13/42", "naklon": 0 },
- "3147": { "label": "13/43", "naklon": 0 },
- "3141": { "label": "13/44", "naklon": 0 },
- "3364": { "label": "13/46", "naklon": 0 },
- "3367": { "label": "13/47", "naklon": 0 },
- "3368": { "label": "13/48", "naklon": 0 },
- "3402": { "label": "13/49", "naklon": 0 },
- "3366": { "label": "13/50", "naklon": 0 },
- "3395": { "label": "13/51", "naklon": 0 },
- "3372": { "label": "13/52", "naklon": 0 },
- "3394": { "label": "13/53", "naklon": 0 },
- "3308": { "label": "13/54", "naklon": 0 },
- "3847": { "label": "13/54/1", "naklon": 0 },
- "3312": { "label": "13/55", "naklon": 3 },
- "3309": { "label": "13/56", "naklon": 3 },
- "3311": { "label": "13/57", "naklon": 3 },
- "3310": { "label": "13/58", "naklon": 3 },
- "4365": { "label": "13/59", "naklon": 3 },
- "4093": { "label": "13/60/1", "naklon": 3 },
- "3304": { "label": "13/61", "naklon": 3 },
- "3307": { "label": "13/62", "naklon": 3 },
- "3271": { "label": "13/63", "naklon": 3 },
- "3301": { "label": "13/64", "naklon": 3 },
- "4366": { "label": "13/65", "naklon": 3 },
- "3300": { "label": "13/66", "naklon": 3 },
- "3185": { "label": "13/67", "naklon": 0 },
- "3184": { "label": "13/68", "naklon": 0 },
- "3188": { "label": "13/69", "naklon": 0 },
- "3343": { "label": "13/71", "naklon": 6 },
- "3819": { "label": "13/71/1", "naklon": 6 },
- "3880": { "label": "13/71/2", "naklon": 6 },
- "3348": { "label": "13/72", "naklon": 6 },
- "3344": { "label": "13/74", "naklon": 6 },
- "3346": { "label": "13/75", "naklon": 6 },
- "3597": { "label": "13/75/1", "naklon": 6 },
- "3345": { "label": "13/76", "naklon": 6 },
- "3322": { "label": "13/77", "naklon": 0 },
- "3325": { "label": "13/78", "naklon": 0 },
- "4310": { "label": "13/78/1", "naklon": 0 },
- "3315": { "label": "13/79", "naklon": 0 },
- "3328": { "label": "13/80", "naklon": 0 },
- "3321": { "label": "13/81", "naklon": 0 },
- "3324": { "label": "13/82", "naklon": 0 },
- "3140": { "label": "13/84", "naklon": 0 },
- "3153": { "label": "13/85", "naklon": 0 },
- "3145": { "label": "13/86", "naklon": 0 },
- "3134": { "label": "13/87", "naklon": 0 },
- "3151": { "label": "13/88", "naklon": 0 },
- "3143": { "label": "13/89", "naklon": 0 },
- "3318": { "label": "13/90", "naklon": 0 },
- "3347": { "label": "13/91", "naklon": 0 },
- "3314": { "label": "13/94", "naklon": 0 },
- "3331": { "label": "13/96", "naklon": 0 },
- "3327": { "label": "13/97", "naklon": 0 },
- "3329": { "label": "13/99", "naklon": 0 },
- "3337": { "label": "13/100", "naklon": 0 },
- "3330": { "label": "13/101", "naklon": 0 },
- "3335": { "label": "13/102", "naklon": 0 },
- "3420": { "label": "13/103", "naklon": 0 },
- "3421": { "label": "13/104", "naklon": 0 },
- "4361": { "label": "13/105", "naklon": 0 },
- "4362": { "label": "13/106", "naklon": 0 },
- "3526": { "label": "13/107", "naklon": 0 },
- "4424": { "label": "13/108", "naklon": null },
- "3561": { "label": "13/109", "naklon": null },
- "3527": { "label": "13/110", "naklon": null },
- "3521": { "label": "13/111", "naklon": null },
- "3552": { "label": "13/112", "naklon": null },
- "3544": { "label": "13/113", "naklon": null },
- "3534": { "label": "13/114", "naklon": null },
- "3516": { "label": "13/115", "naklon": null },
- "3513": { "label": "13/116", "naklon": null },
- "3565": { "label": "13/117", "naklon": null },
- "3866": { "label": "13/118", "naklon": null },
- "3136": { "label": "14/1", "naklon": 0 },
- "3137": { "label": "14/2", "naklon": 0 },
- "3135": { "label": "14/3", "naklon": 0 },
- "3149": { "label": "14/4", "naklon": 0 },
- "3142": { "label": "14/5", "naklon": 0 },
- "3342": { "label": "14/6", "naklon": 0 },
- "3340": { "label": "14/7", "naklon": 0 },
- "3152": { "label": "14/8", "naklon": 0 },
- "3886": { "label": "14/9", "naklon": 0 },
- "3341": { "label": "14/10", "naklon": null },
- "3352": { "label": "14/11", "naklon": null },
- "3396": { "label": "15/1", "naklon": 5 },
- "2784": { "label": "15/2", "naklon": 5 },
- "2788": { "label": "15/3", "naklon": 5 },
- "2801": { "label": "15/4", "naklon": 5 },
- "2815": { "label": "15/5", "naklon": 5 },
- "2829": { "label": "15/6", "naklon": 5 },
- "2796": { "label": "15/7", "naklon": 5 },
- "2803": { "label": "15/8", "naklon": 5 },
- "4304": { "label": "15/8/1", "naklon": 5 },
- "4311": { "label": "15/8/2", "naklon": 5 },
- "2821": { "label": "15/9", "naklon": 5 },
- "3400": { "label": "15/10", "naklon": 5 },
- "2799": { "label": "15/11", "naklon": 5 },
- "2804": { "label": "15/12", "naklon": 5 },
- "4303": { "label": "15/12/1", "naklon": 5 },
- "4309": { "label": "15/12/2", "naklon": 5 },
- "2806": { "label": "15/13", "naklon": 5 },
- "2787": { "label": "15/14", "naklon": 5 },
- "2809": { "label": "15/15", "naklon": 5 },
- "2814": { "label": "15/16", "naklon": 0 },
- "3934": { "label": "15/17", "naklon": 0 },
- "3192": { "label": "15/18", "naklon": 0 },
- "2812": { "label": "15/19", "naklon": 0 },
- "4070": { "label": "15/20", "naklon": 0 },
- "2826": { "label": "15/21", "naklon": 0 },
- "2808": { "label": "15/22", "naklon": 3 },
- "2795": { "label": "15/23", "naklon": 3 },
- "2807": { "label": "15/24", "naklon": 3 },
- "2831": { "label": "15/25", "naklon": 0 },
- "2862": { "label": "15/26", "naklon": null },
- "2861": { "label": "15/27", "naklon": 0 },
- "2866": { "label": "15/28", "naklon": 0 },
- "3546": { "label": "15/28/1", "naklon": 0 },
- "4146": { "label": "15/29", "naklon": 0 },
- "3001": { "label": "15/29/1", "naklon": 0 },
- "2835": { "label": "15/30", "naklon": 0 },
- "2874": { "label": "15/31", "naklon": 0 },
- "2852": { "label": "15/32", "naklon": 0 },
- "2851": { "label": "15/33", "naklon": 0 },
- "3560": { "label": "15/33/1", "naklon": 0 },
- "2858": { "label": "15/34", "naklon": 0 },
- "4306": { "label": "15/34/1", "naklon": 0 },
- "2856": { "label": "15/35", "naklon": 0 },
- "2847": { "label": "15/36", "naklon": 0 },
- "3556": { "label": "15/36/1", "naklon": 0 },
- "3950": { "label": "15/37", "naklon": 0 },
- "2848": { "label": "15/38", "naklon": 0 },
- "2863": { "label": "15/39", "naklon": 0 },
- "4313": { "label": "15/39/1", "naklon": 0 },
- "2873": { "label": "15/40", "naklon": 0 },
- "2984": { "label": "15/40/1", "naklon": 0 },
- "2854": { "label": "15/41", "naklon": 0 },
- "2859": { "label": "15/42", "naklon": 0 },
- "2872": { "label": "15/43", "naklon": 0 },
- "2849": { "label": "15/44", "naklon": 0 },
- "2864": { "label": "15/45", "naklon": 0 },
- "3553": { "label": "15/46", "naklon": null },
- "3021": { "label": "15/47", "naklon": null },
- "3008": { "label": "15/47/1", "naklon": null },
- "3017": { "label": "15/48", "naklon": null },
- "3014": { "label": "15/49", "naklon": null },
- "2981": { "label": "15/50", "naklon": null },
- "3020": { "label": "15/51", "naklon": null },
- "3027": { "label": "15/52", "naklon": null },
- "3006": { "label": "15/53", "naklon": null },
- "3012": { "label": "15/54", "naklon": null },
- "2738": { "label": "15/55", "naklon": 0 },
- "2725": { "label": "15/56", "naklon": 0 },
- "3016": { "label": "15/57", "naklon": null },
- "3005": { "label": "15/58", "naklon": null },
- "3009": { "label": "15/58/1", "naklon": null },
- "3010": { "label": "15/59", "naklon": 0 },
- "3538": { "label": "15/59/1", "naklon": 0 },
- "4145": { "label": "15/59/2", "naklon": 0 },
- "2713": { "label": "15/60", "naklon": 0 },
- "2789": { "label": "15/61", "naklon": 0 },
- "2736": { "label": "15/62", "naklon": 0 },
- "2739": { "label": "15/63", "naklon": 0 },
- "4346": { "label": "15/64", "naklon": 0 },
- "2731": { "label": "15/65", "naklon": 0 },
- "2818": { "label": "15/66", "naklon": 0 },
- "3557": { "label": "15/66/1", "naklon": 0 },
- "2822": { "label": "15/67", "naklon": 0 },
- "2833": { "label": "15/68", "naklon": 0 },
- "2834": { "label": "15/69", "naklon": 0 },
- "3097": { "label": "15/70", "naklon": 0 },
- "2824": { "label": "15/71", "naklon": 0 },
- "2828": { "label": "15/72", "naklon": 0 },
- "2600": { "label": "15/73", "naklon": 0 },
- "4314": { "label": "15/73/1", "naklon": 0 },
- "2832": { "label": "15/74", "naklon": 0 },
- "4360": { "label": "15/75", "naklon": 0 },
- "2846": { "label": "15/76", "naklon": 0 },
- "2584": { "label": "15/77", "naklon": 0 },
- "2843": { "label": "15/78", "naklon": 0 },
- "4308": { "label": "15/78/1", "naklon": 0 },
- "4144": { "label": "15/79", "naklon": null },
- "2844": { "label": "15/80", "naklon": 0 },
- "2842": { "label": "15/81", "naklon": 0 },
- "2838": { "label": "15/82", "naklon": 0 },
- "2837": { "label": "15/83", "naklon": null },
- "3555": { "label": "15/83/1", "naklon": null },
- "2839": { "label": "15/84", "naklon": 0 },
- "2830": { "label": "15/85", "naklon": 0 },
- "4066": { "label": "15/86", "naklon": 0 },
- "2836": { "label": "15/87", "naklon": 0 },
- "2911": { "label": "15/88", "naklon": 0 },
- "2825": { "label": "15/89", "naklon": 0 },
- "2811": { "label": "15/90", "naklon": 0 },
- "3740": { "label": "15/94", "naklon": 15 },
- "2734": { "label": "15/95", "naklon": 15 },
- "3105": { "label": "15/96", "naklon": 15 },
- "2732": { "label": "15/97", "naklon": 15 },
- "2727": { "label": "15/98", "naklon": 15 },
- "2735": { "label": "15/99", "naklon": 15 },
- "3926": { "label": "15/100", "naklon": 15 },
- "2918": { "label": "15/101", "naklon": 0 },
- "2705": { "label": "15/102", "naklon": 10 },
- "2708": { "label": "15/103", "naklon": 10 },
- "2721": { "label": "15/104", "naklon": 10 },
- "2719": { "label": "15/105", "naklon": 10 },
- "2919": { "label": "15/106", "naklon": 10 },
- "3101": { "label": "15/107", "naklon": 10 },
- "2853": { "label": "15/108", "naklon": 10 },
- "2715": { "label": "15/109", "naklon": 10 },
- "2712": { "label": "15/110", "naklon": 0 },
- "2711": { "label": "15/111", "naklon": 0 },
- "2709": { "label": "15/112", "naklon": 0 },
- "2710": { "label": "15/113", "naklon": 0 },
- "2907": { "label": "15/114", "naklon": 0 },
- "2906": { "label": "15/115", "naklon": 0 },
- "2908": { "label": "15/116", "naklon": 0 },
- "2901": { "label": "15/117", "naklon": 0 },
- "2913": { "label": "15/118", "naklon": 0 },
- "3656": { "label": "15/119", "naklon": 0 },
- "2781": { "label": "15/120", "naklon": 0 },
- "2802": { "label": "15/121", "naklon": 0 },
- "2791": { "label": "15/122", "naklon": 0 },
- "2783": { "label": "15/123", "naklon": 0 },
- "2794": { "label": "15/124", "naklon": 0 },
- "3139": { "label": "15/125", "naklon": 0 },
- "3229": { "label": "15/126", "naklon": 5 },
- "3239": { "label": "15/127", "naklon": 5 },
- "3230": { "label": "15/128", "naklon": 5 },
- "4016": { "label": "15/129", "naklon": null },
- "3608": { "label": "16/16A", "naklon": 0 },
- "4151": { "label": "16/16B", "naklon": 0 },
- "3710": { "label": "16/1", "naklon": 0 },
- "3726": { "label": "16/2", "naklon": 0 },
- "3743": { "label": "16/3", "naklon": 0 },
- "3724": { "label": "16/4", "naklon": 0 },
- "3712": { "label": "16/5", "naklon": 0 },
- "3739": { "label": "16/6", "naklon": 0 },
- "3742": { "label": "16/7", "naklon": 0 },
- "3731": { "label": "16/8", "naklon": 0 },
- "3727": { "label": "16/9", "naklon": 0 },
- "3729": { "label": "16/10", "naklon": 0 },
- "3736": { "label": "16/11", "naklon": 0 },
- "3713": { "label": "16/12", "naklon": 0 },
- "3715": { "label": "16/13", "naklon": 0 },
- "3733": { "label": "16/14", "naklon": 0 },
- "3732": { "label": "16/15", "naklon": 0 },
- "3634": { "label": "16/17", "naklon": 0 },
- "3610": { "label": "16/18", "naklon": 0 },
- "3626": { "label": "16/19", "naklon": 0 },
- "3618": { "label": "16/20", "naklon": 0 },
- "3619": { "label": "16/21", "naklon": 0 },
- "3628": { "label": "16/22", "naklon": 0 },
- "3615": { "label": "16/23", "naklon": 0 },
- "3609": { "label": "16/24", "naklon": 0 },
- "3606": { "label": "16/25", "naklon": 0 },
- "3624": { "label": "16/26", "naklon": 0 },
- "3627": { "label": "16/27", "naklon": 0 },
- "3607": { "label": "16/28", "naklon": 0 },
- "4370": { "label": "16/29", "naklon": 0 },
- "3692": { "label": "16/30", "naklon": 0 },
- "3614": { "label": "16/31", "naklon": 0 },
- "3623": { "label": "16/32", "naklon": 0 },
- "4373": { "label": "16/33", "naklon": 0 },
- "3620": { "label": "16/34", "naklon": 0 },
- "3685": { "label": "16/35", "naklon": 0 },
- "3616": { "label": "16/36", "naklon": 0 },
- "3686": { "label": "16/37", "naklon": 0 },
- "3688": { "label": "16/38", "naklon": 0 },
- "3684": { "label": "16/39", "naklon": 0 },
- "3825": { "label": "16/40", "naklon": 0 },
- "3865": { "label": "16/41", "naklon": 0 },
- "3824": { "label": "16/42", "naklon": 0 },
- "3871": { "label": "16/43", "naklon": 0 },
- "3801": { "label": "16/44", "naklon": 0 },
- "3862": { "label": "16/45", "naklon": 0 },
- "3876": { "label": "16/46", "naklon": 0 },
- "3861": { "label": "16/47", "naklon": 0 },
- "4215": { "label": "16/48", "naklon": 0 },
- "3605": { "label": "16/49", "naklon": 10 },
- "3603": { "label": "16/50", "naklon": 10 },
- "3592": { "label": "16/51", "naklon": 10 },
- "3598": { "label": "16/52", "naklon": 10 },
- "3594": { "label": "16/53", "naklon": 10 },
- "3593": { "label": "16/54", "naklon": 10 },
- "3630": { "label": "16/55", "naklon": 10 },
- "3763": { "label": "16/56", "naklon": 10 },
- "3746": { "label": "16/57", "naklon": 10 },
- "3699": { "label": "16/58", "naklon": 0 },
- "3698": { "label": "16/59", "naklon": 0 },
- "3709": { "label": "16/60", "naklon": null },
- "3708": { "label": "16/61", "naklon": 0 },
- "3703": { "label": "16/62", "naklon": null },
- "3700": { "label": "16/63", "naklon": 0 },
- "3701": { "label": "16/64", "naklon": null },
- "3704": { "label": "16/65", "naklon": 0 },
- "3707": { "label": "16/66", "naklon": null },
- "3810": { "label": "16/67", "naklon": 0 },
- "4208": { "label": "16/68", "naklon": null },
- "3867": { "label": "16/69", "naklon": 0 },
- "4372": { "label": "16/70", "naklon": null },
- "3881": { "label": "16/71", "naklon": 0 },
- "4204": { "label": "16/72", "naklon": null },
- "3869": { "label": "16/73", "naklon": 0 },
- "4202": { "label": "16/74", "naklon": null },
- "3830": { "label": "16/75", "naklon": 0 },
- "3870": { "label": "16/76", "naklon": null },
- "3964": { "label": "16/77", "naklon": 0 },
- "3849": { "label": "16/78", "naklon": 0 },
- "3694": { "label": "16/79", "naklon": null },
- "3717": { "label": "16/80", "naklon": 0 },
- "3877": { "label": "16/81", "naklon": null },
- "3755": { "label": "16/82", "naklon": 0 },
- "3725": { "label": "16/83", "naklon": null },
- "3716": { "label": "16/84", "naklon": 0 },
- "3696": { "label": "16/85", "naklon": null },
- "3702": { "label": "16/86", "naklon": 0 },
- "3706": { "label": "16/87", "naklon": null },
- "3850": { "label": "16/88", "naklon": 0 },
- "3848": { "label": "16/89", "naklon": null },
- "3737": { "label": "16/90", "naklon": null },
- "3705": { "label": "16/91", "naklon": 0 },
- "3723": { "label": "16/92", "naklon": null },
- "3842": { "label": "16/93", "naklon": 0 },
- "3735": { "label": "16/94", "naklon": null },
- "3719": { "label": "16/95", "naklon": 0 },
- "3697": { "label": "16/96", "naklon": 0 },
- "3711": { "label": "16/97", "naklon": 0 },
- "4107": { "label": "16/98", "naklon": null },
- "4112": { "label": "16/99", "naklon": 5 },
- "4106": { "label": "16/100", "naklon": 5 },
- "4111": { "label": "16/101", "naklon": 5 },
- "4091": { "label": "16/102", "naklon": null },
- "4104": { "label": "16/103", "naklon": 5 },
- "4094": { "label": "16/104", "naklon": null },
- "4089": { "label": "16/105", "naklon": 5 },
- "4095": { "label": "16/106", "naklon": null },
- "4102": { "label": "16/107", "naklon": 5 },
- "4105": { "label": "16/108", "naklon": null },
- "3859": { "label": "16/109", "naklon": null },
- "4090": { "label": "16/110", "naklon": 5 },
- "4110": { "label": "16/111", "naklon": null },
- "4097": { "label": "16/112", "naklon": 5 },
- "4099": { "label": "16/113", "naklon": null },
- "4096": { "label": "16/114", "naklon": null },
- "4101": { "label": "16/115", "naklon": 5 },
- "4109": { "label": "16/116", "naklon": null },
- "4092": { "label": "16/117", "naklon": 5 },
- "3631": { "label": "16/118", "naklon": null },
- "3632": { "label": "16/119", "naklon": 0 },
- "3641": { "label": "16/120", "naklon": null },
- "3638": { "label": "16/121", "naklon": 0 },
- "3637": { "label": "16/122", "naklon": null },
- "4142": { "label": "16/123", "naklon": null },
- "4147": { "label": "16/124", "naklon": 5 },
- "4139": { "label": "16/125", "naklon": 5 },
- "3172": { "label": "20/30A", "naklon": 2 },
- "3164": { "label": "20/30B", "naklon": 2 },
- "3247": { "label": "20/1", "naklon": 10 },
- "3296": { "label": "20/2", "naklon": 10 },
- "3246": { "label": "20/3", "naklon": 10 },
- "3270": { "label": "20/4", "naklon": 10 },
- "3294": { "label": "20/5", "naklon": 10 },
- "3298": { "label": "20/6", "naklon": 10 },
- "3297": { "label": "20/7", "naklon": 10 },
- "3293": { "label": "20/8", "naklon": 10 },
- "3299": { "label": "20/9", "naklon": 10 },
- "3295": { "label": "20/10", "naklon": 10 },
- "3244": { "label": "20/11", "naklon": 10 },
- "3249": { "label": "20/12", "naklon": 10 },
- "3268": { "label": "20/13", "naklon": 10 },
- "3245": { "label": "20/14", "naklon": 10 },
- "3278": { "label": "20/15", "naklon": 10 },
- "3280": { "label": "20/16", "naklon": 10 },
- "3292": { "label": "20/17", "naklon": 10 },
- "3287": { "label": "20/18", "naklon": 10 },
- "3282": { "label": "20/19", "naklon": 10 },
- "3273": { "label": "20/20", "naklon": 0 },
- "3157": { "label": "20/21", "naklon": 0 },
- "3283": { "label": "20/22", "naklon": 0 },
- "3159": { "label": "20/23", "naklon": 0 },
- "3289": { "label": "20/24", "naklon": 0 },
- "3163": { "label": "20/25", "naklon": 0 },
- "3126": { "label": "20/26", "naklon": 0 },
- "3171": { "label": "20/27", "naklon": 0 },
- "3162": { "label": "20/28", "naklon": 0 },
- "3279": { "label": "20/29", "naklon": 10 },
- "3173": { "label": "20/31", "naklon": 0 },
- "3127": { "label": "20/32", "naklon": 0 },
- "3131": { "label": "20/33", "naklon": 0 },
- "3129": { "label": "20/34", "naklon": 0 },
- "3276": { "label": "20/35", "naklon": 2 },
- "3290": { "label": "20/36", "naklon": 2 },
- "3132": { "label": "20/37", "naklon": 0 },
- "3138": { "label": "20/38", "naklon": 0 },
- "3272": { "label": "20/39", "naklon": 0 },
- "3291": { "label": "20/40", "naklon": 0 },
- "3277": { "label": "20/41", "naklon": 10 },
- "3286": { "label": "20/42", "naklon": 10 },
- "3281": { "label": "20/43", "naklon": 10 },
- "3288": { "label": "20/44", "naklon": 10 },
- "3284": { "label": "20/45", "naklon": 10 },
- "3167": { "label": "20/46", "naklon": 10 },
- "3872": { "label": "20/47", "naklon": 0 },
- "3124": { "label": "20/48", "naklon": 0 },
- "3133": { "label": "20/49", "naklon": 0 },
- "3158": { "label": "20/50", "naklon": 0 },
- "3169": { "label": "20/51", "naklon": 0 },
- "3146": { "label": "20/52", "naklon": 0 },
- "3160": { "label": "20/53", "naklon": 0 },
- "3248": { "label": "20/54", "naklon": 0 },
- "3156": { "label": "20/55", "naklon": 0 },
- "3161": { "label": "20/56", "naklon": 0 },
- "3170": { "label": "20/57", "naklon": 0 },
- "3168": { "label": "20/58", "naklon": 0 },
- "3125": { "label": "20/59", "naklon": 0 },
- "3166": { "label": "20/60", "naklon": 0 },
- "3130": { "label": "20/61", "naklon": 0 },
- "3563": { "label": "20/62", "naklon": 0 },
- "3550": { "label": "20/63", "naklon": null },
- "3269": { "label": "20/67", "naklon": 0 },
- "2921": { "label": "21/1", "naklon": 0 },
- "2707": { "label": "21/2", "naklon": 0 },
- "2723": { "label": "21/3", "naklon": 0 },
- "2716": { "label": "21/4", "naklon": 0 },
- "2717": { "label": "21/5", "naklon": 0 },
- "2720": { "label": "21/6", "naklon": 0 },
- "2722": { "label": "21/7", "naklon": 0 },
- "2718": { "label": "21/8", "naklon": 0 },
- "2724": { "label": "21/9", "naklon": 0 },
- "2742": { "label": "21/10", "naklon": 0 },
- "2743": { "label": "21/11", "naklon": 0 },
- "2733": { "label": "21/12", "naklon": 0 },
- "2903": { "label": "21/14", "naklon": 0 },
- "2917": { "label": "21/15", "naklon": 0 },
- "2897": { "label": "21/16", "naklon": 0 },
- "2914": { "label": "21/17", "naklon": 0 },
- "2898": { "label": "21/18", "naklon": 0 },
- "2773": { "label": "21/19", "naklon": 0 },
- "2895": { "label": "21/20", "naklon": 0 },
- "2896": { "label": "21/21", "naklon": 0 },
- "2771": { "label": "21/22", "naklon": 0 },
- "2772": { "label": "21/23", "naklon": 0 },
- "2793": { "label": "21/24", "naklon": 0 },
- "2902": { "label": "21/25", "naklon": 0 },
- "2910": { "label": "21/26", "naklon": 0 },
- "2909": { "label": "21/27", "naklon": 0 },
- "2920": { "label": "21/28", "naklon": 0 },
- "2916": { "label": "21/29", "naklon": 0 },
- "2904": { "label": "21/30", "naklon": 0 },
- "2915": { "label": "21/31", "naklon": 0 },
- "2905": { "label": "21/32", "naklon": 0 },
- "2900": { "label": "21/33", "naklon": 0 },
- "2899": { "label": "21/34", "naklon": 0 },
- "2741": { "label": "21/36", "naklon": 0 },
- "2714": { "label": "21/37", "naklon": 0 },
- "2701": { "label": "21/38", "naklon": 0 },
- "2703": { "label": "21/39", "naklon": 0 },
- "2704": { "label": "21/40", "naklon": 0 },
- "2702": { "label": "21/41", "naklon": 0 },
- "2706": { "label": "21/42", "naklon": 0 },
- "2776": { "label": "21/43", "naklon": 0 },
- "2770": { "label": "21/44", "naklon": 0 },
- "2786": { "label": "21/45", "naklon": 0 },
- "2779": { "label": "21/46", "naklon": 0 },
- "2782": { "label": "21/47", "naklon": 0 },
- "2785": { "label": "21/48", "naklon": 0 },
- "2769": { "label": "21/49", "naklon": 0 },
- "3354": { "label": "21/50", "naklon": 0 },
- "2778": { "label": "21/51", "naklon": 0 },
- "2775": { "label": "21/52", "naklon": 0 },
- "2780": { "label": "21/53", "naklon": 0 },
- "2790": { "label": "21/54", "naklon": 0 },
- "2792": { "label": "21/55", "naklon": 0 },
- "2774": { "label": "21/56", "naklon": 0 },
- "2630": { "label": "22/1", "naklon": 0 },
- "2631": { "label": "22/2", "naklon": 0 },
- "2632": { "label": "22/3", "naklon": 0 },
- "2633": { "label": "22/4", "naklon": 0 },
- "2634": { "label": "22/5", "naklon": 0 },
- "2636": { "label": "22/6", "naklon": 0 },
- "4367": { "label": "22/7", "naklon": 0 },
- "2637": { "label": "22/8", "naklon": 0 },
- "2638": { "label": "22/9", "naklon": 0 },
- "2639": { "label": "22/10", "naklon": 0 },
- "2640": { "label": "22/11", "naklon": 0 },
- "2641": { "label": "22/12", "naklon": 0 },
- "2642": { "label": "22/13", "naklon": 0 },
- "2643": { "label": "22/14", "naklon": 0 },
- "2644": { "label": "22/15", "naklon": 0 },
- "2645": { "label": "22/16", "naklon": 0 },
- "2646": { "label": "22/17", "naklon": 0 },
- "2647": { "label": "22/18", "naklon": 0 },
- "2648": { "label": "22/19", "naklon": 0 },
- "2649": { "label": "22/20", "naklon": 0 },
- "2650": { "label": "22/21", "naklon": 0 },
- "2651": { "label": "22/22", "naklon": 0 },
- "4103": { "label": "22/23", "naklon": 0 },
- "2653": { "label": "22/24", "naklon": 0 },
- "2654": { "label": "22/25", "naklon": 0 },
- "2655": { "label": "22/26", "naklon": 0 },
- "2656": { "label": "22/27", "naklon": 0 },
- "2657": { "label": "22/28", "naklon": 0 },
- "2658": { "label": "22/29", "naklon": 0 },
- "2659": { "label": "22/30", "naklon": 0 },
- "2660": { "label": "22/31", "naklon": 0 },
- "2661": { "label": "22/32", "naklon": 0 },
- "3015": { "label": "22/32/1", "naklon": 0 },
- "2662": { "label": "22/33", "naklon": 0 },
- "2663": { "label": "22/34", "naklon": 0 },
- "2664": { "label": "22/35", "naklon": 0 },
- "2665": { "label": "22/36", "naklon": 0 },
- "2666": { "label": "22/37", "naklon": 0 },
- "2667": { "label": "22/38", "naklon": 0 },
- "2668": { "label": "22/39", "naklon": 0 },
- "2669": { "label": "22/40", "naklon": null },
- "2670": { "label": "22/41", "naklon": null },
- "2671": { "label": "22/42", "naklon": null },
- "3087": { "label": "23/9A", "naklon": 10 },
- "3090": { "label": "23/9B", "naklon": 10 },
- "3075": { "label": "23/1", "naklon": 0 },
- "3089": { "label": "23/2", "naklon": 0 },
- "3088": { "label": "23/3", "naklon": 0 },
- "3228": { "label": "23/4", "naklon": 10 },
- "2751": { "label": "23/5", "naklon": 10 },
- "3243": { "label": "23/6", "naklon": 10 },
- "4349": { "label": "23/7", "naklon": 10 },
- "3102": { "label": "23/8", "naklon": 10 },
- "3099": { "label": "23/10", "naklon": 10 },
- "3103": { "label": "23/11", "naklon": 10 },
- "3093": { "label": "23/12", "naklon": 10 },
- "3098": { "label": "23/13", "naklon": 10 },
- "3092": { "label": "23/14", "naklon": 10 },
- "3233": { "label": "23/15", "naklon": 0 },
- "3095": { "label": "23/16", "naklon": 0 },
- "4074": { "label": "23/17", "naklon": 0 },
- "2729": { "label": "23/18", "naklon": 0 },
- "3234": { "label": "23/19", "naklon": 0 },
- "3094": { "label": "23/20", "naklon": 0 },
- "2817": { "label": "23/21", "naklon": 0 },
- "3226": { "label": "23/22", "naklon": 0 },
- "3225": { "label": "23/23", "naklon": 0 },
- "3237": { "label": "23/24", "naklon": 0 },
- "4250": { "label": "23/25", "naklon": 0 },
- "3059": { "label": "23/26", "naklon": 10 },
- "3238": { "label": "23/27", "naklon": 10 },
- "3242": { "label": "23/28", "naklon": 10 },
- "3236": { "label": "23/29", "naklon": 10 },
- "3112": { "label": "23/30", "naklon": 10 },
- "3224": { "label": "23/31", "naklon": 0 },
- "4298": { "label": "23/32", "naklon": 10 },
- "4150": { "label": "23/33", "naklon": 10 },
- "3091": { "label": "23/34", "naklon": 10 },
- "3771": { "label": "25/1", "naklon": 5 },
- "3777": { "label": "25/2", "naklon": 5 },
- "3749": { "label": "25/3", "naklon": 5 },
- "3769": { "label": "25/4", "naklon": 5 },
- "3765": { "label": "25/5", "naklon": 5 },
- "3785": { "label": "25/6", "naklon": 5 },
- "3761": { "label": "25/7", "naklon": 5 },
- "3758": { "label": "25/8", "naklon": 5 },
- "3766": { "label": "25/9", "naklon": 5 },
- "3779": { "label": "25/10", "naklon": 5 },
- "3899": { "label": "25/11", "naklon": 10 },
- "3922": { "label": "25/12", "naklon": 10 },
- "3912": { "label": "25/13", "naklon": 10 },
- "3933": { "label": "25/14", "naklon": 10 },
- "3921": { "label": "25/15", "naklon": 10 },
- "4300": { "label": "25/16", "naklon": 10 },
- "3927": { "label": "25/17", "naklon": 10 },
- "3212": { "label": "25/18", "naklon": 10 },
- "3208": { "label": "25/19", "naklon": 10 },
- "3207": { "label": "25/20", "naklon": 10 },
- "4294": { "label": "25/21", "naklon": 10 },
- "3209": { "label": "25/22", "naklon": 10 },
- "3745": { "label": "25/23", "naklon": 10 },
- "3762": { "label": "25/24", "naklon": 10 },
- "3215": { "label": "25/25", "naklon": 10 },
- "3210": { "label": "25/26", "naklon": 10 },
- "3211": { "label": "25/27", "naklon": 10 },
- "3206": { "label": "25/28", "naklon": 10 },
- "3918": { "label": "25/29", "naklon": 5 },
- "3928": { "label": "25/30", "naklon": 5 },
- "3917": { "label": "25/31", "naklon": 5 },
- "4029": { "label": "25/32", "naklon": 0 },
- "4038": { "label": "25/33", "naklon": 0 },
- "4022": { "label": "25/34", "naklon": 0 },
- "3937": { "label": "25/35", "naklon": 0 },
- "3190": { "label": "25/36", "naklon": 0 },
- "3835": { "label": "25/37", "naklon": 0 },
- "3201": { "label": "25/38", "naklon": 0 },
- "3193": { "label": "25/39", "naklon": 0 },
- "3191": { "label": "25/40", "naklon": 0 },
- "3203": { "label": "25/41", "naklon": 0 },
- "4301": { "label": "25/42", "naklon": 0 },
- "3223": { "label": "25/43", "naklon": 0 },
- "3202": { "label": "25/44", "naklon": 0 },
- "3205": { "label": "25/45", "naklon": 0 },
- "3194": { "label": "25/46", "naklon": 0 },
- "3198": { "label": "25/47", "naklon": 0 },
- "3204": { "label": "25/48", "naklon": 0 },
- "3200": { "label": "25/49", "naklon": 0 },
- "3216": { "label": "25/50", "naklon": 0 },
- "3932": { "label": "25/51", "naklon": 5 },
- "3923": { "label": "25/52", "naklon": 5 },
- "3913": { "label": "25/53", "naklon": 5 },
- "3900": { "label": "25/54", "naklon": 5 },
- "4189": { "label": "25/55", "naklon": 10 },
- "4191": { "label": "25/56", "naklon": 10 },
- "3790": { "label": "25/57", "naklon": 10 },
- "4190": { "label": "25/58", "naklon": 10 },
- "4302": { "label": "25/59", "naklon": 0 },
- "4351": { "label": "25/60", "naklon": 0 },
- "4075": { "label": "25/61", "naklon": 0 },
- "4071": { "label": "25/62", "naklon": 0 },
- "3784": { "label": "25/63", "naklon": 0 },
- "4065": { "label": "25/64", "naklon": 0 },
- "4297": { "label": "25/65", "naklon": 0 },
- "4295": { "label": "25/66", "naklon": 0 },
- "4299": { "label": "25/67", "naklon": 0 },
- "3772": { "label": "25/68", "naklon": 0 },
- "3941": { "label": "25/69", "naklon": 0 },
- "3782": { "label": "25/70", "naklon": 0 },
- "4068": { "label": "25/71", "naklon": 0 },
- "4073": { "label": "25/72", "naklon": 0 },
- "3901": { "label": "25/73", "naklon": 5 },
- "4296": { "label": "25/74", "naklon": 5 },
- "3910": { "label": "25/75", "naklon": 5 },
- "4293": { "label": "25/76", "naklon": 5 },
- "3919": { "label": "25/77", "naklon": 5 },
- "3924": { "label": "25/78", "naklon": 5 },
- "3909": { "label": "25/79", "naklon": 5 },
- "3896": { "label": "25/80", "naklon": 5 },
- "3911": { "label": "25/81", "naklon": 5 },
- "2819": { "label": "25/82", "naklon": 15 },
- "3776": { "label": "25/83", "naklon": 15 },
- "3752": { "label": "25/84", "naklon": 15 },
- "4353": { "label": "25/85", "naklon": 15 },
- "3791": { "label": "25/86", "naklon": 0 },
- "3770": { "label": "25/87", "naklon": 0 },
- "3760": { "label": "25/88", "naklon": 0 },
- "3115": { "label": "25/89", "naklon": 0 },
- "3738": { "label": "25/90", "naklon": 0 },
- "3748": { "label": "25/91", "naklon": 0 },
- "3753": { "label": "25/92", "naklon": 0 },
- "3775": { "label": "25/93", "naklon": 0 },
- "3778": { "label": "25/94", "naklon": 5 },
- "4078": { "label": "25/95", "naklon": 5 },
- "4088": { "label": "25/96", "naklon": 5 },
- "3856": { "label": "25/97", "naklon": 5 },
- "4084": { "label": "25/98", "naklon": 5 },
- "4069": { "label": "25/99", "naklon": 5 },
- "4188": { "label": "25/100", "naklon": 5 },
- "4064": { "label": "25/101", "naklon": 5 },
- "3792": { "label": "25/102", "naklon": 5 },
- "3780": { "label": "25/103", "naklon": 5 },
- "4034": { "label": "25/104", "naklon": 5 },
- "4072": { "label": "25/105", "naklon": 5 },
- "3884": { "label": "25/106", "naklon": 5 },
- "3793": { "label": "25/107", "naklon": 5 },
- "3863": { "label": "25/108", "naklon": 5 },
- "3855": { "label": "25/109", "naklon": 5 },
- "3846": { "label": "33/1", "naklon": 0 },
- "3943": { "label": "33/2", "naklon": 0 },
- "3903": { "label": "33/3", "naklon": 0 },
- "3982": { "label": "33/4", "naklon": 0 },
- "3879": { "label": "33/5", "naklon": 0 },
- "3887": { "label": "33/6", "naklon": 0 },
- "3920": { "label": "33/7", "naklon": 5 },
- "3942": { "label": "33/8", "naklon": 5 },
- "3829": { "label": "33/9", "naklon": null },
- "3452": { "label": "34/79A", "naklon": 6 },
- "3460": { "label": "34/79B", "naklon": 6 },
- "3443": { "label": "34/90A", "naklon": 6 },
- "3445": { "label": "34/90B", "naklon": 6 },
- "3457": { "label": "34/90C", "naklon": 6 },
- "3461": { "label": "34/97A", "naklon": 6 },
- "3463": { "label": "34/97B", "naklon": 6 },
- "3426": { "label": "34/98A", "naklon": 6 },
- "3444": { "label": "34/98B", "naklon": 6 },
- "3453": { "label": "34/99A", "naklon": 6 },
- "3455": { "label": "34/99B", "naklon": 6 },
- "4009": { "label": "34/1", "naklon": 0 },
- "3602": { "label": "34/2", "naklon": 0 },
- "3441": { "label": "34/3", "naklon": 0 },
- "3464": { "label": "34/4", "naklon": 0 },
- "3883": { "label": "34/5", "naklon": 0 },
- "4098": { "label": "34/6", "naklon": 0 },
- "4003": { "label": "34/7", "naklon": 0 },
- "4004": { "label": "34/8", "naklon": 0 },
- "3888": { "label": "34/9", "naklon": 0 },
- "3997": { "label": "34/10", "naklon": 0 },
- "4006": { "label": "34/11", "naklon": 0 },
- "4000": { "label": "34/12", "naklon": 0 },
- "4011": { "label": "34/13", "naklon": 0 },
- "3999": { "label": "34/14", "naklon": 0 },
- "3981": { "label": "34/15", "naklon": 0 },
- "3988": { "label": "34/16", "naklon": 0 },
- "3986": { "label": "34/17", "naklon": 0 },
- "3998": { "label": "34/18", "naklon": 0 },
- "3983": { "label": "34/19", "naklon": 0 },
- "4005": { "label": "34/20", "naklon": 0 },
- "4001": { "label": "34/21", "naklon": 0 },
- "4008": { "label": "34/22", "naklon": 0 },
- "4002": { "label": "34/23", "naklon": 0 },
- "3996": { "label": "34/24", "naklon": 0 },
- "4007": { "label": "34/25", "naklon": 0 },
- "4113": { "label": "34/26", "naklon": 15 },
- "3595": { "label": "34/27", "naklon": 5 },
- "3599": { "label": "34/28", "naklon": 5 },
- "3601": { "label": "34/29", "naklon": 5 },
- "4205": { "label": "34/30", "naklon": 0 },
- "3987": { "label": "34/31", "naklon": null },
- "4214": { "label": "34/32", "naklon": 0 },
- "4226": { "label": "34/33", "naklon": 0 },
- "4209": { "label": "34/34", "naklon": 0 },
- "4201": { "label": "34/35", "naklon": 0 },
- "3440": { "label": "34/36", "naklon": 0 },
- "3465": { "label": "34/37", "naklon": 0 },
- "3446": { "label": "34/38", "naklon": 0 },
- "4039": { "label": "34/39", "naklon": 5 },
- "4057": { "label": "34/40", "naklon": 5 },
- "3985": { "label": "34/41", "naklon": 0 },
- "3882": { "label": "34/42", "naklon": 0 },
- "4040": { "label": "34/43", "naklon": 5 },
- "3231": { "label": "34/44", "naklon": 0 },
- "3227": { "label": "34/45", "naklon": 0 },
- "3431": { "label": "34/46", "naklon": 0 },
- "4013": { "label": "34/47", "naklon": 0 },
- "4045": { "label": "34/48", "naklon": 0 },
- "3949": { "label": "34/49", "naklon": 0 },
- "3953": { "label": "34/50", "naklon": 0 },
- "3952": { "label": "34/51", "naklon": 0 },
- "3995": { "label": "34/52", "naklon": 0 },
- "3992": { "label": "34/53", "naklon": 0 },
- "4198": { "label": "34/54", "naklon": 0 },
- "3935": { "label": "34/55", "naklon": 0 },
- "4050": { "label": "34/56", "naklon": 0 },
- "4049": { "label": "34/57", "naklon": 0 },
- "4054": { "label": "34/58", "naklon": 0 },
- "3663": { "label": "34/59", "naklon": 6 },
- "3661": { "label": "34/60", "naklon": 6 },
- "3664": { "label": "34/61", "naklon": 6 },
- "3660": { "label": "34/62", "naklon": 6 },
- "3662": { "label": "34/63", "naklon": 6 },
- "3665": { "label": "34/65", "naklon": 6 },
- "3667": { "label": "34/66", "naklon": 6 },
- "3675": { "label": "34/67", "naklon": 6 },
- "3666": { "label": "34/68", "naklon": 6 },
- "3652": { "label": "34/69", "naklon": 6 },
- "3458": { "label": "34/70", "naklon": 6 },
- "4425": { "label": "34/70/1", "naklon": 6 },
- "3459": { "label": "34/71", "naklon": 6 },
- "3435": { "label": "34/72", "naklon": 6 },
- "3448": { "label": "34/73", "naklon": 6 },
- "3451": { "label": "34/74", "naklon": 6 },
- "3442": { "label": "34/75", "naklon": 6 },
- "3449": { "label": "34/76", "naklon": 6 },
- "3450": { "label": "34/77", "naklon": 6 },
- "3433": { "label": "34/78", "naklon": 6 },
- "3432": { "label": "34/80", "naklon": 12 },
- "3470": { "label": "34/81", "naklon": 12 },
- "3438": { "label": "34/82", "naklon": 12 },
- "3439": { "label": "34/83", "naklon": 12 },
- "4028": { "label": "34/84", "naklon": 5 },
- "3596": { "label": "34/85", "naklon": 5 },
- "4021": { "label": "34/86", "naklon": 5 },
- "3437": { "label": "34/87", "naklon": 12 },
- "3428": { "label": "34/88", "naklon": 12 },
- "3430": { "label": "34/89", "naklon": 12 },
- "3454": { "label": "34/91", "naklon": 6 },
- "3492": { "label": "34/92", "naklon": 6 },
- "3462": { "label": "34/93", "naklon": 6 },
- "3427": { "label": "34/94", "naklon": 6 },
- "3434": { "label": "34/95", "naklon": 6 },
- "3456": { "label": "34/96", "naklon": 6 },
- "4307": { "label": "34/98/1", "naklon": 6 },
- "3968": { "label": "35/1", "naklon": 0 },
- "3969": { "label": "35/2", "naklon": 0 },
- "3947": { "label": "35/3", "naklon": 0 },
- "3979": { "label": "35/4", "naklon": 0 },
- "3959": { "label": "35/5", "naklon": 0 },
- "3948": { "label": "35/6", "naklon": 0 },
- "3961": { "label": "35/7", "naklon": 0 },
- "3956": { "label": "35/8", "naklon": 0 },
- "3604": { "label": "35/9", "naklon": 0 },
- "3944": { "label": "35/10", "naklon": 0 },
- "3960": { "label": "35/11", "naklon": 0 },
- "3958": { "label": "35/12", "naklon": 0 },
- "4036": { "label": "35/13", "naklon": 5 },
- "3893": { "label": "35/18", "naklon": 5 },
- "4108": { "label": "35/19", "naklon": 5 },
- "4017": { "label": "35/20", "naklon": 5 },
- "3963": { "label": "35/21", "naklon": 0 },
- "3658": { "label": "35/22", "naklon": 0 },
- "3975": { "label": "35/23", "naklon": 0 },
- "3980": { "label": "35/24", "naklon": 0 },
- "4012": { "label": "35/25", "naklon": 0 },
- "3655": { "label": "35/26", "naklon": 0 },
- "3962": { "label": "35/27", "naklon": 0 },
- "3945": { "label": "35/28", "naklon": 0 },
- "3569": { "label": "35/29", "naklon": 0 },
- "3429": { "label": "35/30", "naklon": 0 },
- "3657": { "label": "35/31", "naklon": 0 },
- "3646": { "label": "35/32", "naklon": 0 },
- "3622": { "label": "35/33", "naklon": 0 },
- "3612": { "label": "35/34", "naklon": 0 },
- "3955": { "label": "35/35", "naklon": 0 },
- "3878": { "label": "35/37", "naklon": 0 },
- "3965": { "label": "35/38", "naklon": 0 },
- "3970": { "label": "35/39", "naklon": 0 },
- "3611": { "label": "35/40", "naklon": 0 },
- "2635": { "label": "35/41", "naklon": 0 },
- "3978": { "label": "35/42", "naklon": 0 },
- "4213": { "label": "35/43", "naklon": 0 },
- "3984": { "label": "35/44", "naklon": 0 },
- "4218": { "label": "35/45", "naklon": 0 },
- "3973": { "label": "35/46", "naklon": 0 },
- "3974": { "label": "35/47", "naklon": 0 },
- "3759": { "label": "35/48", "naklon": 0 },
- "3844": { "label": "35/49", "naklon": 0 },
- "3804": { "label": "35/50", "naklon": 0 },
- "3831": { "label": "35/51", "naklon": 0 },
- "3643": { "label": "35/52", "naklon": 0 },
- "3966": { "label": "35/53", "naklon": 0 },
- "3971": { "label": "35/54", "naklon": 0 },
- "3650": { "label": "35/55", "naklon": 6 },
- "3651": { "label": "35/56", "naklon": 6 },
- "3669": { "label": "35/57", "naklon": 6 },
- "3648": { "label": "35/58", "naklon": 6 },
- "3645": { "label": "35/59", "naklon": 6 },
- "3659": { "label": "35/60", "naklon": 6 },
- "3647": { "label": "35/61", "naklon": 6 },
- "3644": { "label": "35/62", "naklon": 6 },
- "3671": { "label": "35/63", "naklon": 6 },
- "3682": { "label": "35/64", "naklon": 6 },
- "3672": { "label": "35/65", "naklon": 6 },
- "3683": { "label": "35/66", "naklon": 6 },
- "3673": { "label": "35/67", "naklon": 6 },
- "3674": { "label": "35/68", "naklon": 6 },
- "3679": { "label": "35/69", "naklon": 6 },
- "3649": { "label": "35/70", "naklon": 6 },
- "3687": { "label": "35/71", "naklon": 6 },
- "3677": { "label": "35/72", "naklon": 6 },
- "3690": { "label": "35/73", "naklon": 6 },
- "3691": { "label": "35/74", "naklon": 6 },
- "3676": { "label": "35/75", "naklon": 6 },
- "3680": { "label": "35/76", "naklon": 6 },
- "3668": { "label": "35/77", "naklon": 6 },
- "3681": { "label": "35/78", "naklon": 6 },
- "3670": { "label": "35/79", "naklon": 6 },
- "3689": { "label": "35/80", "naklon": 6 },
- "3678": { "label": "35/81", "naklon": 6 },
- "3693": { "label": "35/82", "naklon": 6 },
- "3654": { "label": "35/83", "naklon": null },
- "4086": { "label": "36/1", "naklon": 0 },
- "4085": { "label": "36/2", "naklon": 0 },
- "4083": { "label": "36/3", "naklon": 0 },
- "4087": { "label": "36/4", "naklon": 0 },
- "4077": { "label": "36/5", "naklon": 0 },
- "4082": { "label": "36/6", "naklon": 0 },
- "4186": { "label": "36/7", "naklon": 0 },
- "4206": { "label": "36/8", "naklon": 0 },
- "4080": { "label": "36/9", "naklon": 0 },
- "4081": { "label": "36/10", "naklon": 0 },
- "4210": { "label": "36/11", "naklon": 0 },
- "4079": { "label": "36/12", "naklon": 0 },
- "4076": { "label": "36/13", "naklon": 0 },
- "3852": { "label": "36/14", "naklon": 0 },
- "2813": { "label": "36/15", "naklon": 0 },
- "4219": { "label": "36/16", "naklon": 0 },
- "3104": { "label": "37/1A", "naklon": 15 },
- "3121": { "label": "37/1B", "naklon": 15 },
- "3113": { "label": "37/2", "naklon": 10 },
- "3118": { "label": "37/3", "naklon": 10 },
- "3111": { "label": "37/4", "naklon": 10 },
- "4020": { "label": "37/5", "naklon": 10 },
- "3119": { "label": "37/6", "naklon": 10 },
- "3110": { "label": "37/7", "naklon": 10 },
- "3108": { "label": "37/8", "naklon": 10 },
- "3107": { "label": "37/12", "naklon": 0 },
- "3199": { "label": "37/13", "naklon": 0 },
- "3120": { "label": "37/14", "naklon": 0 },
- "3122": { "label": "37/15", "naklon": 0 },
- "3908": { "label": "37/16", "naklon": 0 },
- "3114": { "label": "37/17", "naklon": 0 },
- "3105": { "label": "37/18", "naklon": 0 },
- "3116": { "label": "37/19", "naklon": 0 },
- "3106": { "label": "37/20", "naklon": 0 },
- "2887": { "label": "37/21", "naklon": 5 },
- "2888": { "label": "37/22", "naklon": 5 },
- "2877": { "label": "37/23", "naklon": 5 },
- "2891": { "label": "37/24", "naklon": 5 },
- "2886": { "label": "37/25", "naklon": 5 },
- "2892": { "label": "37/26", "naklon": 5 },
- "2882": { "label": "37/27", "naklon": 5 },
- "2883": { "label": "37/28", "naklon": 5 },
- "2876": { "label": "37/29", "naklon": 5 },
- "3109": { "label": "37/30", "naklon": 5 },
- "4152": { "label": "37/31", "naklon": 5 },
- "3117": { "label": "37/32", "naklon": 5 },
- "2870": { "label": "37/33", "naklon": 5 },
- "2867": { "label": "37/34", "naklon": 0 },
- "2865": { "label": "37/35", "naklon": 0 },
- "3096": { "label": "37/36", "naklon": 0 },
- "2871": { "label": "37/37", "naklon": 0 },
- "2884": { "label": "37/38", "naklon": 0 },
- "2855": { "label": "37/39", "naklon": 0 },
- "2878": { "label": "37/40", "naklon": 0 },
- "2889": { "label": "37/41", "naklon": 0 },
- "2879": { "label": "37/42", "naklon": 0 },
- "2850": { "label": "37/43", "naklon": 0 },
- "2894": { "label": "37/44", "naklon": 0 },
- "2880": { "label": "37/45", "naklon": 0 },
- "2893": { "label": "37/46", "naklon": 0 },
- "2890": { "label": "37/47", "naklon": 0 },
- "4355": { "label": "37/48", "naklon": 0 },
- "2885": { "label": "37/49", "naklon": 0 },
- "2875": { "label": "37/50", "naklon": 0 },
- "3486": { "label": "38/30A", "naklon": 5 },
- "3714": { "label": "38/30B", "naklon": 0 },
- "3483": { "label": "38/32A", "naklon": 5 },
- "3496": { "label": "38/32B", "naklon": 0 },
- "3487": { "label": "38/35A", "naklon": 5 },
- "3498": { "label": "38/35B", "naklon": 5 },
- "3578": { "label": "38/38A", "naklon": 5 },
- "3508": { "label": "38/38B", "naklon": 5 },
- "3787": { "label": "38/59A", "naklon": 5 },
- "3491": { "label": "38/59B", "naklon": 5 },
- "3568": { "label": "38/1", "naklon": null },
- "3502": { "label": "38/2", "naklon": 0 },
- "3836": { "label": "38/3", "naklon": 0 },
- "3588": { "label": "38/4", "naklon": 0 },
- "3493": { "label": "38/5", "naklon": 0 },
- "3580": { "label": "38/6", "naklon": 0 },
- "3572": { "label": "38/7", "naklon": 0 },
- "3506": { "label": "38/8", "naklon": 0 },
- "3503": { "label": "38/9", "naklon": 0 },
- "3579": { "label": "38/10", "naklon": 0 },
- "3586": { "label": "38/11", "naklon": 0 },
- "3495": { "label": "38/12", "naklon": 5 },
- "3492": { "label": "38/13", "naklon": 5 },
- "3532": { "label": "38/14", "naklon": 5 },
- "3574": { "label": "38/15", "naklon": 5 },
- "4140": { "label": "38/16", "naklon": 5 },
- "3795": { "label": "38/17", "naklon": 5 },
- "3788": { "label": "38/18", "naklon": 5 },
- "3796": { "label": "38/19", "naklon": 5 },
- "3797": { "label": "38/20", "naklon": 5 },
- "3798": { "label": "38/21", "naklon": 5 },
- "3786": { "label": "38/22", "naklon": 5 },
- "4067": { "label": "38/23", "naklon": 5 },
- "3773": { "label": "38/24", "naklon": 5 },
- "3774": { "label": "38/25", "naklon": 5 },
- "3789": { "label": "38/26", "naklon": 5 },
- "3520": { "label": "38/27", "naklon": null },
- "3577": { "label": "38/29", "naklon": 5 },
- "3530": { "label": "38/31", "naklon": null },
- "3488": { "label": "38/33", "naklon": 5 },
- "3505": { "label": "38/34", "naklon": 5 },
- "3497": { "label": "38/36", "naklon": 5 },
- "3490": { "label": "38/37", "naklon": 5 },
- "3585": { "label": "38/39", "naklon": 5 },
- "3582": { "label": "38/40", "naklon": 5 },
- "3507": { "label": "38/41", "naklon": 5 },
- "3484": { "label": "38/42", "naklon": 5 },
- "3501": { "label": "38/43", "naklon": 5 },
- "3581": { "label": "38/44", "naklon": 5 },
- "4192": { "label": "38/45", "naklon": 5 },
- "3576": { "label": "38/46", "naklon": 5 },
- "3489": { "label": "38/47", "naklon": 5 },
- "3573": { "label": "38/48", "naklon": 5 },
- "3504": { "label": "38/49", "naklon": 5 },
- "3794": { "label": "38/50", "naklon": 5 },
- "3485": { "label": "38/51", "naklon": 5 },
- "3482": { "label": "38/52", "naklon": 5 },
- "3575": { "label": "38/53", "naklon": 5 },
- "3499": { "label": "38/54", "naklon": 5 },
- "3494": { "label": "38/55", "naklon": 5 },
- "3583": { "label": "38/56", "naklon": 5 },
- "3570": { "label": "38/57", "naklon": 5 },
- "3500": { "label": "38/58", "naklon": 0 },
- "3510": { "label": "38/63", "naklon": null },
- "3512": { "label": "38/64", "naklon": null },
- "3535": { "label": "38/67", "naklon": null },
- "3531": { "label": "38/68", "naklon": null },
- "3537": { "label": "38/69", "naklon": null },
- "3522": { "label": "39/1", "naklon": 10 },
- "4018": { "label": "39/2", "naklon": 10 },
- "4019": { "label": "39/3", "naklon": 10 },
- "4154": { "label": "39/4", "naklon": 5 },
- "3907": { "label": "39/5", "naklon": 5 },
- "4148": { "label": "39/6", "naklon": 0 },
- "4153": { "label": "39/7", "naklon": 0 },
- "3938": { "label": "39/8", "naklon": 0 },
- "3802": { "label": "39/9", "naklon": 0 },
- "4015": { "label": "39/10", "naklon": 0 },
- "3929": { "label": "39/11", "naklon": 0 },
- "3946": { "label": "39/12", "naklon": 0 },
- "4014": { "label": "39/13", "naklon": 0 },
- "4155": { "label": "39/14", "naklon": 0 },
- "4149": { "label": "39/15", "naklon": 0 },
- "3642": { "label": "39/16", "naklon": 0 },
- "3636": { "label": "39/17", "naklon": 5 },
- "3991": { "label": "39/18", "naklon": 0 },
- "3994": { "label": "39/19", "naklon": 0 },
- "3990": { "label": "39/20", "naklon": 0 },
- "3967": { "label": "39/21", "naklon": 0 },
- "3977": { "label": "39/22", "naklon": 0 },
- "3757": { "label": "39/23", "naklon": 15 },
- "3633": { "label": "39/24", "naklon": 15 },
- "3744": { "label": "39/25", "naklon": 15 },
- "4023": { "label": "39/26", "naklon": 5 },
- "3720": { "label": "39/27", "naklon": 5 },
- "3734": { "label": "39/28", "naklon": 5 },
- "3741": { "label": "39/29", "naklon": 5 },
- "3721": { "label": "39/30", "naklon": 5 },
- "3845": { "label": "39/31", "naklon": 0 },
- "3840": { "label": "39/32", "naklon": 0 },
- "3837": { "label": "39/33", "naklon": null },
- "3839": { "label": "39/34", "naklon": 0 },
- "3542": { "label": "41/1", "naklon": null },
- "3566": { "label": "41/2", "naklon": null },
- "3548": { "label": "41/3", "naklon": null },
- "3515": { "label": "41/4", "naklon": null },
- "3559": { "label": "41/5", "naklon": null },
- "3509": { "label": "41/6", "naklon": null },
- "3524": { "label": "41/7", "naklon": null },
- "3518": { "label": "41/8", "naklon": null },
- "3182": { "label": "41/9", "naklon": null },
- "3187": { "label": "41/10", "naklon": null },
- "3195": { "label": "41/11", "naklon": 0 },
- "3857": { "label": "41/12", "naklon": 0 },
- "3183": { "label": "41/13", "naklon": 0 },
- "3177": { "label": "41/14", "naklon": 0 },
- "3189": { "label": "41/15", "naklon": 0 },
- "3186": { "label": "41/16", "naklon": 0 },
- "3178": { "label": "42/1", "naklon": 0 },
- "3219": { "label": "42/2", "naklon": 0 },
- "3475": { "label": "42/3", "naklon": 0 },
- "3175": { "label": "42/4", "naklon": 0 },
- "3222": { "label": "42/5", "naklon": 0 },
- "3221": { "label": "42/6", "naklon": 0 },
- "3181": { "label": "42/7", "naklon": 0 },
- "3180": { "label": "42/8", "naklon": 0 },
- "3218": { "label": "42/9", "naklon": 0 },
- "3176": { "label": "42/10", "naklon": 0 },
- "3174": { "label": "42/11", "naklon": 0 },
- "3220": { "label": "42/12", "naklon": 0 },
- "3533": { "label": "42/13", "naklon": null },
- "3543": { "label": "42/14", "naklon": null },
- "3554": { "label": "42/15", "naklon": null },
- "3549": { "label": "42/16", "naklon": null },
- "2857": { "label": "43/1", "naklon": 5 },
- "2752": { "label": "43/2", "naklon": 5 },
- "2753": { "label": "43/3", "naklon": 5 },
- "3024": { "label": "43/4", "naklon": 5 },
- "2754": { "label": "43/5", "naklon": 5 },
- "4423": { "label": "43/6", "naklon": 5 },
- "4368": { "label": "43/7", "naklon": 5 },
- "2978": { "label": "43/8", "naklon": 5 },
- "2868": { "label": "43/9", "naklon": 5 },
- "4377": { "label": "43/10", "naklon": 5 },
- "2757": { "label": "43/11", "naklon": 5 },
- "2970": { "label": "43/12", "naklon": 5 },
- "2758": { "label": "43/13", "naklon": 5 },
- "4378": { "label": "43/14", "naklon": 5 },
- "2759": { "label": "43/15", "naklon": 5 },
- "4342": { "label": "43/16", "naklon": 5 },
- "3026": { "label": "43/17", "naklon": null },
- "2986": { "label": "43/18", "naklon": null },
- "4343": { "label": "43/19", "naklon": null },
- "2760": { "label": "43/20", "naklon": null },
- "4379": { "label": "43/21", "naklon": null },
- "2971": { "label": "43/22", "naklon": null },
- "2761": { "label": "43/23", "naklon": null },
- "2762": { "label": "43/24", "naklon": null },
- "4339": { "label": "43/25", "naklon": null },
- "4380": { "label": "43/26", "naklon": null },
- "2975": { "label": "43/27", "naklon": null },
- "3003": { "label": "43/28", "naklon": null },
- "4338": { "label": "43/29", "naklon": null },
- "3002": { "label": "43/30", "naklon": null },
- "4345": { "label": "43/31", "naklon": null },
- "2979": { "label": "43/32", "naklon": null },
- "2989": { "label": "43/33", "naklon": null },
- "2996": { "label": "43/34", "naklon": null },
- "2972": { "label": "43/35", "naklon": null },
- "2988": { "label": "43/36", "naklon": null },
- "4344": { "label": "43/37", "naklon": null },
- "3022": { "label": "43/38", "naklon": null },
- "4341": { "label": "43/39", "naklon": null },
- "2983": { "label": "43/40", "naklon": null },
- "2995": { "label": "43/41", "naklon": null },
- "2763": { "label": "43/42", "naklon": null },
- "2764": { "label": "43/43", "naklon": null },
- "2765": { "label": "43/44", "naklon": null },
- "2766": { "label": "43/45", "naklon": null },
- "2767": { "label": "43/46", "naklon": null },
- "2768": { "label": "43/47", "naklon": null },
- "3018": { "label": "43/48", "naklon": null },
- "2982": { "label": "43/49", "naklon": null },
- "3019": { "label": "43/50", "naklon": 0 },
- "3013": { "label": "43/51", "naklon": null },
- "3007": { "label": "43/52", "naklon": null },
- "2980": { "label": "43/53", "naklon": null },
- "3011": { "label": "43/54", "naklon": null },
- "2672": { "label": "43/55", "naklon": null },
- "2673": { "label": "43/56", "naklon": null },
- "2674": { "label": "43/57", "naklon": null },
- "2675": { "label": "43/58", "naklon": null },
- "2676": { "label": "43/59", "naklon": null },
- "2677": { "label": "43/60", "naklon": null },
- "2678": { "label": "43/61", "naklon": null },
- "2679": { "label": "43/62", "naklon": null },
- "2680": { "label": "43/63", "naklon": null },
- "2840": { "label": "43/64", "naklon": null },
- "2682": { "label": "43/65", "naklon": null },
- "2683": { "label": "43/66", "naklon": null },
- "2684": { "label": "43/67", "naklon": 0 },
- "2685": { "label": "43/68", "naklon": null },
- "2686": { "label": "43/69", "naklon": null },
- "2687": { "label": "43/70", "naklon": null },
- "2688": { "label": "43/71", "naklon": null },
- "2689": { "label": "43/72", "naklon": null },
- "2690": { "label": "43/73", "naklon": null },
- "2691": { "label": "43/74", "naklon": null },
- "2692": { "label": "43/75", "naklon": null },
- "2693": { "label": "43/76", "naklon": 0 },
- "2694": { "label": "43/77", "naklon": null },
- "2695": { "label": "43/78", "naklon": null },
- "2696": { "label": "43/79", "naklon": 0 },
- "2697": { "label": "43/80", "naklon": null },
- "2698": { "label": "43/81", "naklon": 0 },
- "2699": { "label": "43/82", "naklon": null },
- "2700": { "label": "43/83", "naklon": 0 },
- "2744": { "label": "43/84", "naklon": null },
- "2745": { "label": "43/85", "naklon": 0 },
- "2746": { "label": "43/86", "naklon": null },
- "2747": { "label": "43/87", "naklon": 0 },
- "2748": { "label": "43/88", "naklon": null },
- "2749": { "label": "43/89", "naklon": 0 },
- "2841": { "label": "43/90", "naklon": null },
- "4237": { "label": "45/1", "naklon": 5 },
- "4226": { "label": "45/2", "naklon": 5 },
- "4242": { "label": "45/3", "naklon": 5 },
- "4179": { "label": "45/4", "naklon": 5 },
- "4247": { "label": "45/5", "naklon": 5 },
- "4245": { "label": "45/6", "naklon": 5 },
- "3872": { "label": "45/7", "naklon": 5 },
- "4175": { "label": "45/8", "naklon": 5 },
- "4236": { "label": "45/9", "naklon": 5 },
- "4170": { "label": "45/10", "naklon": 5 },
- "4238": { "label": "45/11", "naklon": 5 },
- "4246": { "label": "45/12", "naklon": 5 },
- "4166": { "label": "45/13", "naklon": 5 },
- "4227": { "label": "45/14", "naklon": 5 },
- "4171": { "label": "45/15", "naklon": 5 },
- "4180": { "label": "45/16", "naklon": 5 },
- "4244": { "label": "45/17", "naklon": 5 },
- "4199": { "label": "45/18", "naklon": 5 },
- "4239": { "label": "45/19", "naklon": 5 },
- "4207": { "label": "45/20", "naklon": 5 },
- "4223": { "label": "45/21", "naklon": 5 },
- "4230": { "label": "45/22", "naklon": 5 },
- "4233": { "label": "45/23", "naklon": 5 },
- "4222": { "label": "45/24", "naklon": 5 },
- "4217": { "label": "45/25", "naklon": 5 },
- "4243": { "label": "45/26", "naklon": 5 },
- "4200": { "label": "45/27", "naklon": 5 },
- "4228": { "label": "45/28", "naklon": 5 },
- "4211": { "label": "45/29", "naklon": 5 },
- "4234": { "label": "45/30", "naklon": 5 },
- "4235": { "label": "45/31", "naklon": 5 },
- "4203": { "label": "45/32", "naklon": 5 },
- "4240": { "label": "45/33", "naklon": 5 },
- "4224": { "label": "45/34", "naklon": 5 },
- "4232": { "label": "45/35", "naklon": 5 },
- "4231": { "label": "45/36", "naklon": 5 },
- "4161": { "label": "45/37", "naklon": 5 },
- "4225": { "label": "45/38", "naklon": 5 },
- "4241": { "label": "45/39", "naklon": 5 },
- "4229": { "label": "45/40", "naklon": 5 },
- "4221": { "label": "45/41", "naklon": 5 },
- "4212": { "label": "45/42", "naklon": 5 },
- "4216": { "label": "45/43", "naklon": 5 },
- "3864": { "label": "45/44", "naklon": null },
- "3806": { "label": "46/1", "naklon": 5 },
- "3813": { "label": "46/2", "naklon": 5 },
- "3815": { "label": "46/3", "naklon": 5 },
- "3807": { "label": "46/4", "naklon": 5 },
- "3895": { "label": "46/5", "naklon": 5 },
- "3809": { "label": "46/6", "naklon": 5 },
- "3820": { "label": "46/7", "naklon": 5 },
- "3805": { "label": "46/8", "naklon": 5 },
- "3894": { "label": "46/9", "naklon": 0 },
- "4055": { "label": "46/10", "naklon": 0 },
- "3812": { "label": "46/11", "naklon": 5 },
- "3822": { "label": "46/12", "naklon": 5 },
- "3821": { "label": "46/13", "naklon": 5 },
- "3808": { "label": "46/14", "naklon": 5 },
- "3799": { "label": "46/15", "naklon": 5 },
- "3816": { "label": "46/16", "naklon": 5 },
- "3751": { "label": "46/17", "naklon": 5 },
- "3814": { "label": "46/18", "naklon": 5 },
- "4044": { "label": "46/19", "naklon": 0 },
- "3931": { "label": "46/20", "naklon": 0 },
- "3902": { "label": "46/21", "naklon": 5 },
- "3916": { "label": "46/22", "naklon": 5 },
- "3892": { "label": "46/23", "naklon": 5 },
- "3914": { "label": "46/24", "naklon": 5 },
- "3898": { "label": "46/25", "naklon": 5 },
- "3897": { "label": "46/26", "naklon": 5 },
- "3885": { "label": "46/27", "naklon": 5 },
- "3906": { "label": "46/28", "naklon": 5 },
- "3930": { "label": "46/29", "naklon": 0 },
- "3936": { "label": "46/30", "naklon": 0 },
- "3860": { "label": "46/31", "naklon": 5 },
- "3841": { "label": "46/32", "naklon": 5 },
- "3873": { "label": "46/33", "naklon": 5 },
- "3854": { "label": "46/34", "naklon": 5 },
- "3939": { "label": "46/35", "naklon": 5 },
- "3858": { "label": "46/36", "naklon": 5 },
- "3940": { "label": "46/37", "naklon": 5 },
- "4035": { "label": "46/38", "naklon": 5 },
- "3373": { "label": "47/1", "naklon": 0 },
- "3374": { "label": "47/2", "naklon": 0 },
- "3384": { "label": "47/3", "naklon": 0 },
- "3385": { "label": "47/4", "naklon": 0 },
- "4051": { "label": "48/1", "naklon": 5 },
- "4041": { "label": "48/2", "naklon": 5 },
- "4056": { "label": "48/3", "naklon": 5 },
- "3875": { "label": "48/4", "naklon": 5 },
- "4061": { "label": "48/5", "naklon": 5 },
- "4047": { "label": "48/6", "naklon": 5 },
- "4060": { "label": "48/7", "naklon": 5 },
- "4059": { "label": "48/8", "naklon": 5 },
- "4058": { "label": "48/9", "naklon": 5 },
- "3635": { "label": "48/10", "naklon": 5 },
- "3640": { "label": "48/11", "naklon": 5 },
- "3747": { "label": "48/12", "naklon": 5 },
- "3629": { "label": "48/13", "naklon": 5 },
- "4048": { "label": "48/14", "naklon": 5 },
- "4063": { "label": "48/15", "naklon": 5 },
- "4062": { "label": "48/16", "naklon": 5 },
- "4043": { "label": "48/17", "naklon": 5 },
- "4052": { "label": "48/18", "naklon": 5 },
- "4042": { "label": "48/19", "naklon": 5 },
- "4053": { "label": "48/20", "naklon": 5 },
- "4167": { "label": "50/15A", "naklon": null },
- "4159": { "label": "50/15B", "naklon": null },
- "4183": { "label": "50/1", "naklon": 0 },
- "4157": { "label": "50/2", "naklon": 0 },
- "4160": { "label": "50/3", "naklon": 0 },
- "4173": { "label": "50/4", "naklon": 0 },
- "4177": { "label": "50/5", "naklon": 0 },
- "4174": { "label": "50/6", "naklon": 0 },
- "4178": { "label": "50/7", "naklon": 0 },
- "4195": { "label": "50/8", "naklon": 0 },
- "4169": { "label": "50/9", "naklon": 0 },
- "4162": { "label": "50/10", "naklon": 0 },
- "4158": { "label": "50/11", "naklon": 0 },
- "4182": { "label": "50/12", "naklon": 0 },
- "4194": { "label": "50/13", "naklon": 0 },
- "4184": { "label": "50/14", "naklon": 0 },
- "4197": { "label": "50/16", "naklon": null },
- "4164": { "label": "50/17", "naklon": null },
- "3306": { "label": "50/18", "naklon": null },
- "4168": { "label": "50/19", "naklon": null },
- "4193": { "label": "50/20", "naklon": null },
- "4187": { "label": "50/21", "naklon": null },
- "4163": { "label": "50/22", "naklon": null },
- "4165": { "label": "50/23", "naklon": null },
- "4185": { "label": "50/24", "naklon": null },
- "3904": { "label": "50/25", "naklon": null },
- "2619": { "label": "53/1", "naklon": 0 },
- "2623": { "label": "53/2", "naklon": 0 },
- "2617": { "label": "53/3", "naklon": 0 },
- "2622": { "label": "53/4", "naklon": 0 },
- "2618": { "label": "53/5", "naklon": 0 },
- "2626": { "label": "53/6", "naklon": 0 },
- "2869": { "label": "53/7", "naklon": 0 },
- "2613": { "label": "53/8", "naklon": 0 },
- "2608": { "label": "53/9", "naklon": 0 },
- "2611": { "label": "53/10", "naklon": 0 },
- "2598": { "label": "53/11", "naklon": 0 },
- "3528": { "label": "53/12", "naklon": 0 },
- "3545": { "label": "53/13", "naklon": 0 },
- "2620": { "label": "53/14", "naklon": 0 },
- "2612": { "label": "53/15", "naklon": 0 },
- "2615": { "label": "53/16", "naklon": 0 },
- "3722": { "label": "53/17", "naklon": 0 },
- "2624": { "label": "53/18", "naklon": 0 },
- "2609": { "label": "53/19", "naklon": 0 },
- "2625": { "label": "53/20", "naklon": 0 },
- "2602": { "label": "53/21", "naklon": 0 },
- "2610": { "label": "53/22", "naklon": 0 },
- "2599": { "label": "53/23", "naklon": 0 },
- "2605": { "label": "53/24", "naklon": 0 },
- "2593": { "label": "53/25", "naklon": 0 },
- "3074": { "label": "53/26", "naklon": 0 },
- "2740": { "label": "53/27", "naklon": 0 },
- "2614": { "label": "53/28", "naklon": 0 },
- "2601": { "label": "53/29", "naklon": 0 },
- "4196": { "label": "53/30", "naklon": 0 },
- "2607": { "label": "53/31", "naklon": 0 },
- "2582": { "label": "53/32", "naklon": 0 },
- "2594": { "label": "53/33", "naklon": 0 },
- "2589": { "label": "53/34", "naklon": 0 },
- "2596": { "label": "53/35", "naklon": 0 },
- "2603": { "label": "53/36", "naklon": 0 },
- "2597": { "label": "53/37", "naklon": 0 },
- "2590": { "label": "53/38", "naklon": 0 },
- "2581": { "label": "53/39", "naklon": 0 },
- "2583": { "label": "53/40", "naklon": 0 },
- "2580": { "label": "53/41", "naklon": 0 },
- "2579": { "label": "53/42", "naklon": 0 },
- "2797": { "label": "53/43", "naklon": 0 },
- "2577": { "label": "53/44", "naklon": 0 },
- "2586": { "label": "53/45", "naklon": 0 },
- "2588": { "label": "53/46", "naklon": 0 },
- "2591": { "label": "53/47", "naklon": 0 },
- "2592": { "label": "53/48", "naklon": 0 },
- "2573": { "label": "53/49", "naklon": 0 },
- "2595": { "label": "53/50", "naklon": 0 },
- "2587": { "label": "53/51", "naklon": 0 },
- "2578": { "label": "53/52", "naklon": 0 },
- "2574": { "label": "53/53", "naklon": 0 },
- "2571": { "label": "53/54", "naklon": 0 },
- "2570": { "label": "53/55", "naklon": 0 },
- "2576": { "label": "53/56", "naklon": 0 },
- "2881": { "label": "53/57", "naklon": 0 },
- "2575": { "label": "53/58", "naklon": 0 },
- "2572": { "label": "53/59", "naklon": 0 },
- "2569": { "label": "53/60", "naklon": 0 },
- "4324": { "label": "55/1", "naklon": 0 },
- "4319": { "label": "55/2", "naklon": 0 },
- "4327": { "label": "55/3", "naklon": 0 },
- "4333": { "label": "55/4", "naklon": 0 },
- "4332": { "label": "55/5", "naklon": 0 },
- "4320": { "label": "55/6", "naklon": 0 },
- "4317": { "label": "55/7", "naklon": 0 },
- "4318": { "label": "55/8", "naklon": 0 },
- "4328": { "label": "55/9", "naklon": 0 },
- "4323": { "label": "55/10", "naklon": 0 },
- "4325": { "label": "55/11", "naklon": 0 },
- "4326": { "label": "55/12", "naklon": 0 },
- "4316": { "label": "55/13", "naklon": 0 },
- "4322": { "label": "55/14", "naklon": 0 },
- "4331": { "label": "55/15", "naklon": 0 },
- "4321": { "label": "55/16", "naklon": 0 },
- "4315": { "label": "55/17", "naklon": 0 },
- "4329": { "label": "55/18", "naklon": 0 },
- "4334": { "label": "55/19", "naklon": 0 },
- "4330": { "label": "55/20", "naklon": 0 }
-};
-
-
-let svetlaSorted = [{ "label": "1/3A", "node": 3993, "naklon": 0 },
-{ "label": "1/3B", "node": 3989, "naklon": 15 },
-{ "label": "1/1", "node": 3976, "naklon": 0 },
-{ "label": "1/2", "node": 4181, "naklon": 0 },
-{ "label": "1/4", "node": 4376, "naklon": 15 },
-{ "label": "1/5", "node": 3868, "naklon": 15 },
-{ "label": "1/6", "node": 3728, "naklon": 15 },
-{ "label": "1/7", "node": 3730, "naklon": 0 },
-{ "label": "1/8", "node": 4374, "naklon": 0 },
-{ "label": "1/9", "node": 3718, "naklon": 15 },
-{ "label": "1/10", "node": 4375, "naklon": 15 },
-{ "label": "1/11", "node": 4172, "naklon": 15 },
-{ "label": "1/12", "node": 4176, "naklon": 15 },
-{ "label": "2/1", "node": 3800, "naklon": 5 },
-{ "label": "2/2", "node": 3823, "naklon": 5 },
-{ "label": "2/3", "node": 3905, "naklon": 5 },
-{ "label": "2/4", "node": 3803, "naklon": 5 },
-{ "label": "2/5", "node": 3817, "naklon": 5 },
-{ "label": "2/6", "node": 3818, "naklon": 5 },
-{ "label": "2/7", "node": 3811, "naklon": 5 },
-{ "label": "2/8", "node": 3915, "naklon": 5 },
-{ "label": "2/9", "node": 3843, "naklon": 10 },
-{ "label": "2/10", "node": 3827, "naklon": 10 },
-{ "label": "2/11", "node": 4220, "naklon": 10 },
-{ "label": "2/12", "node": 3826, "naklon": 10 },
-{ "label": "2/13", "node": 3834, "naklon": 10 },
-{ "label": "2/14", "node": 3838, "naklon": 10 },
-{ "label": "2/15", "node": 2823, "naklon": 10 },
-{ "label": "2/16", "node": 3750, "naklon": 10 },
-{ "label": "2/17", "node": 3378, "naklon": 0 },
-{ "label": "2/18", "node": 3376, "naklon": 0 },
-{ "label": "2/19", "node": 3379, "naklon": 0 },
-{ "label": "2/20", "node": 3285, "naklon": 0 },
-{ "label": "2/21", "node": 3382, "naklon": 0 },
-{ "label": "2/22", "node": 3383, "naklon": 0 },
-{ "label": "2/24", "node": 3375, "naklon": 0 },
-{ "label": "2/25", "node": 3381, "naklon": 0 },
-{ "label": "2/26", "node": 3380, "naklon": 0 },
-{ "label": "2/27", "node": 3828, "naklon": 10 },
-{ "label": "2/28", "node": 3377, "naklon": 0 },
-{ "label": "7/1", "node": 3591, "naklon": 0 },
-{ "label": "7/2", "node": 3587, "naklon": 0 },
-{ "label": "7/3", "node": 3468, "naklon": 0 },
-{ "label": "7/4", "node": 3466, "naklon": 0 },
-{ "label": "7/5", "node": 3474, "naklon": 0 },
-{ "label": "7/6", "node": 3481, "naklon": 0 },
-{ "label": "7/7", "node": 3589, "naklon": 0 },
-{ "label": "7/8", "node": 3472, "naklon": 0 },
-{ "label": "7/9", "node": 3473, "naklon": 0 },
-{ "label": "7/10", "node": 3584, "naklon": 0 },
-{ "label": "7/11", "node": 3571, "naklon": 0 },
-{ "label": "7/12", "node": 3476, "naklon": 0 },
-{ "label": "7/13", "node": 3590, "naklon": 0 },
-{ "label": "7/14", "node": 3478, "naklon": 0 },
-{ "label": "7/15", "node": 3471, "naklon": 0 },
-{ "label": "7/16", "node": 3467, "naklon": 0 },
-{ "label": "7/17", "node": 3479, "naklon": 0 },
-{ "label": "7/18", "node": 3480, "naklon": 0 },
-{ "label": "7/19", "node": 3477, "naklon": 0 },
-{ "label": "12/1", "node": 3362, "naklon": 0 },
-{ "label": "12/2", "node": 3355, "naklon": 0 },
-{ "label": "12/3", "node": 3356, "naklon": 0 },
-{ "label": "12/4", "node": 3349, "naklon": 0 },
-{ "label": "12/5", "node": 3357, "naklon": 0 },
-{ "label": "12/6", "node": 3350, "naklon": 0 },
-{ "label": "12/7", "node": 3353, "naklon": 0 },
-{ "label": "12/8", "node": 3539, "naklon": 0 },
-{ "label": "12/9", "node": 3050, "naklon": 0 },
-{ "label": "12/10", "node": 3361, "naklon": 0 },
-{ "label": "12/11", "node": 3360, "naklon": 0 },
-{ "label": "12/12", "node": 3358, "naklon": 0 },
-{ "label": "12/13", "node": 3541, "naklon": 0 },
-{ "label": "12/14", "node": 3551, "naklon": 0 },
-{ "label": "12/15", "node": 3514, "naklon": 0 },
-{ "label": "12/16", "node": 3547, "naklon": 0 },
-{ "label": "12/17", "node": 3562, "naklon": 0 },
-{ "label": "12/18", "node": 3525, "naklon": 0 },
-{ "label": "12/19", "node": 3558, "naklon": 0 },
-{ "label": "12/20", "node": 3511, "naklon": 0 },
-{ "label": "12/21", "node": 3058, "naklon": 0 },
-{ "label": "12/22", "node": 3062, "naklon": 0 },
-{ "label": "12/23", "node": 3070, "naklon": 0 },
-{ "label": "12/24", "node": 3447, "naklon": 0 },
-{ "label": "12/25", "node": 3056, "naklon": 0 },
-{ "label": "12/26", "node": 3057, "naklon": 0 },
-{ "label": "12/27", "node": 3071, "naklon": 0 },
-{ "label": "12/28", "node": 3061, "naklon": 0 },
-{ "label": "12/29", "node": 3069, "naklon": 0 },
-{ "label": "12/30", "node": 3077, "naklon": 0 },
-{ "label": "12/31", "node": 3080, "naklon": 0 },
-{ "label": "12/32", "node": 3081, "naklon": 0 },
-{ "label": "12/33", "node": 3078, "naklon": 0 },
-{ "label": "12/34", "node": 4037, "naklon": 0 },
-{ "label": "12/35", "node": 3067, "naklon": 0 },
-{ "label": "12/36", "node": 3051, "naklon": 0 },
-{ "label": "12/37", "node": 2924, "naklon": 0 },
-{ "label": "12/38", "node": 3060, "naklon": 0 },
-{ "label": "12/39", "node": 3073, "naklon": 0 },
-{ "label": "12/40", "node": 3469, "naklon": 0 },
-{ "label": "12/41", "node": 2923, "naklon": 0 },
-{ "label": "12/42", "node": 2925, "naklon": 0 },
-{ "label": "12/43", "node": 3359, "naklon": 0 },
-{ "label": "12/44", "node": 3055, "naklon": 0 },
-{ "label": "12/45", "node": 2922, "naklon": 0 },
-{ "label": "12/46", "node": 3084, "naklon": 0 },
-{ "label": "12/47", "node": 3064, "naklon": 0 },
-{ "label": "12/48", "node": 3066, "naklon": 0 },
-{ "label": "12/49", "node": 3072, "naklon": 0 },
-{ "label": "13/13A", "node": 3415, "naklon": 0 },
-{ "label": "13/13B", "node": 3409, "naklon": 0 },
-{ "label": "13/13C", "node": 3399, "naklon": 0 },
-{ "label": "13/29A", "node": 3410, "naklon": 0 },
-{ "label": "13/29B", "node": 3407, "naklon": 0 },
-{ "label": "13/34A", "node": 3405, "naklon": 0 },
-{ "label": "13/34B", "node": 3404, "naklon": 0 },
-{ "label": "13/45A", "node": 3392, "naklon": 0 },
-{ "label": "13/45B", "node": 3386, "naklon": 0 },
-{ "label": "13/60A", "node": 3303, "naklon": 3 },
-{ "label": "13/60B", "node": 3302, "naklon": 3 },
-{ "label": "13/70A", "node": 3319, "naklon": 6 },
-{ "label": "13/70B", "node": 3317, "naklon": 6 },
-{ "label": "13/70C", "node": 3326, "naklon": 6 },
-{ "label": "13/73A", "node": 3351, "naklon": 6 },
-{ "label": "13/73B", "node": 3313, "naklon": 6 },
-{ "label": "13/83A", "node": 3316, "naklon": 0 },
-{ "label": "13/83B", "node": 3320, "naklon": 0 },
-{ "label": "13/95A", "node": 3336, "naklon": 0 },
-{ "label": "13/95B", "node": 3323, "naklon": 0 },
-{ "label": "13/98A", "node": 3339, "naklon": 0 },
-{ "label": "13/98B", "node": 3333, "naklon": 0 },
-{ "label": "13/1", "node": 3425, "naklon": 0 },
-{ "label": "13/2", "node": 3419, "naklon": 0 },
-{ "label": "13/3", "node": 3416, "naklon": 0 },
-{ "label": "13/4", "node": 3332, "naklon": 0 },
-{ "label": "13/5", "node": 3422, "naklon": 0 },
-{ "label": "13/6", "node": 3417, "naklon": 0 },
-{ "label": "13/7", "node": 3418, "naklon": 0 },
-{ "label": "13/8", "node": 3424, "naklon": 0 },
-{ "label": "13/9", "node": 3334, "naklon": 0 },
-{ "label": "13/10", "node": 4363, "naklon": 0 },
-{ "label": "13/11", "node": 3423, "naklon": 0 },
-{ "label": "13/12", "node": 3406, "naklon": 0 },
-{ "label": "13/14", "node": 3411, "naklon": 0 },
-{ "label": "13/15", "node": 3412, "naklon": 0 },
-{ "label": "13/16", "node": 3413, "naklon": 0 },
-{ "label": "13/17", "node": 3414, "naklon": 0 },
-{ "label": "13/18", "node": 3391, "naklon": 0 },
-{ "label": "13/19", "node": 3370, "naklon": 0 },
-{ "label": "13/20", "node": 3369, "naklon": 0 },
-{ "label": "13/21", "node": 3408, "naklon": 0 },
-{ "label": "13/22", "node": 3393, "naklon": 0 },
-{ "label": "13/23", "node": 3128, "naklon": 0 },
-{ "label": "13/24", "node": 3197, "naklon": 0 },
-{ "label": "13/25", "node": 4364, "naklon": 0 },
-{ "label": "13/26", "node": 3155, "naklon": 0 },
-{ "label": "13/27", "node": 3196, "naklon": 0 },
-{ "label": "13/28", "node": 3144, "naklon": 0 },
-{ "label": "13/30", "node": 3150, "naklon": 0 },
-{ "label": "13/31", "node": 3390, "naklon": 0 },
-{ "label": "13/32", "node": 3401, "naklon": 0 },
-{ "label": "13/33", "node": 3275, "naklon": 0 },
-{ "label": "13/35", "node": 3371, "naklon": 0 },
-{ "label": "13/36", "node": 3389, "naklon": 0 },
-{ "label": "13/37", "node": 3388, "naklon": 0 },
-{ "label": "13/38", "node": 3365, "naklon": 0 },
-{ "label": "13/39", "node": 3363, "naklon": 0 },
-{ "label": "13/40", "node": 3397, "naklon": 0 },
-{ "label": "13/40/1", "node": 3567, "naklon": 0 },
-{ "label": "13/41", "node": 3387, "naklon": 0 },
-{ "label": "13/42", "node": 3403, "naklon": 0 },
-{ "label": "13/43", "node": 3147, "naklon": 0 },
-{ "label": "13/44", "node": 3141, "naklon": 0 },
-{ "label": "13/46", "node": 3364, "naklon": 0 },
-{ "label": "13/47", "node": 3367, "naklon": 0 },
-{ "label": "13/48", "node": 3368, "naklon": 0 },
-{ "label": "13/49", "node": 3402, "naklon": 0 },
-{ "label": "13/50", "node": 3366, "naklon": 0 },
-{ "label": "13/51", "node": 3395, "naklon": 0 },
-{ "label": "13/52", "node": 3372, "naklon": 0 },
-{ "label": "13/53", "node": 3394, "naklon": 0 },
-{ "label": "13/54", "node": 3308, "naklon": 0 },
-{ "label": "13/54/1", "node": 3847, "naklon": 0 },
-{ "label": "13/55", "node": 3312, "naklon": 3 },
-{ "label": "13/56", "node": 3309, "naklon": 3 },
-{ "label": "13/57", "node": 3311, "naklon": 3 },
-{ "label": "13/58", "node": 3310, "naklon": 3 },
-{ "label": "13/59", "node": 4365, "naklon": 3 },
-{ "label": "13/60/1", "node": 4093, "naklon": 3 },
-{ "label": "13/61", "node": 3304, "naklon": 3 },
-{ "label": "13/62", "node": 3307, "naklon": 3 },
-{ "label": "13/63", "node": 3271, "naklon": 3 },
-{ "label": "13/64", "node": 3301, "naklon": 3 },
-{ "label": "13/65", "node": 4366, "naklon": 3 },
-{ "label": "13/66", "node": 3300, "naklon": 3 },
-{ "label": "13/67", "node": 3185, "naklon": 0 },
-{ "label": "13/68", "node": 3184, "naklon": 0 },
-{ "label": "13/69", "node": 3188, "naklon": 0 },
-{ "label": "13/71", "node": 3343, "naklon": 6 },
-{ "label": "13/71/1", "node": 3819, "naklon": 6 },
-{ "label": "13/71/2", "node": 3880, "naklon": 6 },
-{ "label": "13/72", "node": 3348, "naklon": 6 },
-{ "label": "13/74", "node": 3344, "naklon": 6 },
-{ "label": "13/75", "node": 3346, "naklon": 6 },
-{ "label": "13/75/1", "node": 3597, "naklon": 6 },
-{ "label": "13/76", "node": 3345, "naklon": 6 },
-{ "label": "13/77", "node": 3322, "naklon": 0 },
-{ "label": "13/78", "node": 3325, "naklon": 0 },
-{ "label": "13/78/1", "node": 4310, "naklon": 0 },
-{ "label": "13/79", "node": 3315, "naklon": 0 },
-{ "label": "13/80", "node": 3328, "naklon": 0 },
-{ "label": "13/81", "node": 3321, "naklon": 0 },
-{ "label": "13/82", "node": 3324, "naklon": 0 },
-{ "label": "13/84", "node": 3140, "naklon": 0 },
-{ "label": "13/85", "node": 3153, "naklon": 0 },
-{ "label": "13/86", "node": 3145, "naklon": 0 },
-{ "label": "13/87", "node": 3134, "naklon": 0 },
-{ "label": "13/88", "node": 3151, "naklon": 0 },
-{ "label": "13/89", "node": 3143, "naklon": 0 },
-{ "label": "13/90", "node": 3318, "naklon": 0 },
-{ "label": "13/91", "node": 3347, "naklon": 0 },
-{ "label": "13/94", "node": 3314, "naklon": 0 },
-{ "label": "13/96", "node": 3331, "naklon": 0 },
-{ "label": "13/97", "node": 3327, "naklon": 0 },
-{ "label": "13/99", "node": 3329, "naklon": 0 },
-{ "label": "13/100", "node": 3337, "naklon": 0 },
-{ "label": "13/101", "node": 3330, "naklon": 0 },
-{ "label": "13/102", "node": 3335, "naklon": 0 },
-{ "label": "13/103", "node": 3420, "naklon": 0 },
-{ "label": "13/104", "node": 3421, "naklon": 0 },
-{ "label": "13/105", "node": 4361, "naklon": 0 },
-{ "label": "13/106", "node": 4362, "naklon": 0 },
-{ "label": "13/107", "node": 3526, "naklon": 0 },
-{ "label": "13/108", "node": 4424, "naklon": null },
-{ "label": "13/109", "node": 3561, "naklon": null },
-{ "label": "13/110", "node": 3527, "naklon": null },
-{ "label": "13/111", "node": 3521, "naklon": null },
-{ "label": "13/112", "node": 3552, "naklon": null },
-{ "label": "13/113", "node": 3544, "naklon": null },
-{ "label": "13/114", "node": 3534, "naklon": null },
-{ "label": "13/115", "node": 3516, "naklon": null },
-{ "label": "13/116", "node": 3513, "naklon": null },
-{ "label": "13/117", "node": 3565, "naklon": null },
-{ "label": "13/118", "node": 3866, "naklon": null },
-{ "label": "14/1", "node": 3136, "naklon": 0 },
-{ "label": "14/2", "node": 3137, "naklon": 0 },
-{ "label": "14/3", "node": 3135, "naklon": 0 },
-{ "label": "14/4", "node": 3149, "naklon": 0 },
-{ "label": "14/5", "node": 3142, "naklon": 0 },
-{ "label": "14/6", "node": 3342, "naklon": 0 },
-{ "label": "14/7", "node": 3340, "naklon": 0 },
-{ "label": "14/8", "node": 3152, "naklon": 0 },
-{ "label": "14/9", "node": 3886, "naklon": 0 },
-{ "label": "14/10", "node": 3341, "naklon": null },
-{ "label": "14/11", "node": 3352, "naklon": null },
-{ "label": "15/1", "node": 3396, "naklon": 5 },
-{ "label": "15/2", "node": 2784, "naklon": 5 },
-{ "label": "15/3", "node": 2788, "naklon": 5 },
-{ "label": "15/4", "node": 2801, "naklon": 5 },
-{ "label": "15/5", "node": 2815, "naklon": 5 },
-{ "label": "15/6", "node": 2829, "naklon": 5 },
-{ "label": "15/7", "node": 2796, "naklon": 5 },
-{ "label": "15/8", "node": 2803, "naklon": 5 },
-{ "label": "15/8/1", "node": 4304, "naklon": 5 },
-{ "label": "15/8/2", "node": 4311, "naklon": 5 },
-{ "label": "15/9", "node": 2821, "naklon": 5 },
-{ "label": "15/10", "node": 3400, "naklon": 5 },
-{ "label": "15/11", "node": 2799, "naklon": 5 },
-{ "label": "15/12", "node": 2804, "naklon": 5 },
-{ "label": "15/12/1", "node": 4303, "naklon": 5 },
-{ "label": "15/12/2", "node": 4309, "naklon": 5 },
-{ "label": "15/13", "node": 2806, "naklon": 5 },
-{ "label": "15/14", "node": 2787, "naklon": 5 },
-{ "label": "15/15", "node": 2809, "naklon": 5 },
-{ "label": "15/16", "node": 2814, "naklon": 0 },
-{ "label": "15/17", "node": 3934, "naklon": 0 },
-{ "label": "15/18", "node": 3192, "naklon": 0 },
-{ "label": "15/19", "node": 2812, "naklon": 0 },
-{ "label": "15/20", "node": 4070, "naklon": 0 },
-{ "label": "15/21", "node": 2826, "naklon": 0 },
-{ "label": "15/22", "node": 2808, "naklon": 3 },
-{ "label": "15/23", "node": 2795, "naklon": 3 },
-{ "label": "15/24", "node": 2807, "naklon": 3 },
-{ "label": "15/25", "node": 2831, "naklon": 0 },
-{ "label": "15/26", "node": 2862, "naklon": null },
-{ "label": "15/27", "node": 2861, "naklon": 0 },
-{ "label": "15/28", "node": 2866, "naklon": 0 },
-{ "label": "15/28/1", "node": 3546, "naklon": 0 },
-{ "label": "15/29", "node": 4146, "naklon": 0 },
-{ "label": "15/29/1", "node": 3001, "naklon": 0 },
-{ "label": "15/30", "node": 2835, "naklon": 0 },
-{ "label": "15/31", "node": 2874, "naklon": 0 },
-{ "label": "15/32", "node": 2852, "naklon": 0 },
-{ "label": "15/33", "node": 2851, "naklon": 0 },
-{ "label": "15/33/1", "node": 3560, "naklon": 0 },
-{ "label": "15/34", "node": 2858, "naklon": 0 },
-{ "label": "15/34/1", "node": 4306, "naklon": 0 },
-{ "label": "15/35", "node": 2856, "naklon": 0 },
-{ "label": "15/36", "node": 2847, "naklon": 0 },
-{ "label": "15/36/1", "node": 3556, "naklon": 0 },
-{ "label": "15/37", "node": 3950, "naklon": 0 },
-{ "label": "15/38", "node": 2848, "naklon": 0 },
-{ "label": "15/39", "node": 2863, "naklon": 0 },
-{ "label": "15/39/1", "node": 4313, "naklon": 0 },
-{ "label": "15/40", "node": 2873, "naklon": 0 },
-{ "label": "15/40/1", "node": 2984, "naklon": 0 },
-{ "label": "15/41", "node": 2854, "naklon": 0 },
-{ "label": "15/42", "node": 2859, "naklon": 0 },
-{ "label": "15/43", "node": 2872, "naklon": 0 },
-{ "label": "15/44", "node": 2849, "naklon": 0 },
-{ "label": "15/45", "node": 2864, "naklon": 0 },
-{ "label": "15/46", "node": 3553, "naklon": null },
-{ "label": "15/47", "node": 3021, "naklon": null },
-{ "label": "15/47/1", "node": 3008, "naklon": null },
-{ "label": "15/48", "node": 3017, "naklon": null },
-{ "label": "15/49", "node": 3014, "naklon": null },
-{ "label": "15/50", "node": 2981, "naklon": null },
-{ "label": "15/51", "node": 3020, "naklon": null },
-{ "label": "15/52", "node": 3027, "naklon": null },
-{ "label": "15/53", "node": 3006, "naklon": null },
-{ "label": "15/54", "node": 3012, "naklon": null },
-{ "label": "15/55", "node": 2738, "naklon": 0 },
-{ "label": "15/56", "node": 2725, "naklon": 0 },
-{ "label": "15/57", "node": 3016, "naklon": null },
-{ "label": "15/58", "node": 3005, "naklon": null },
-{ "label": "15/58/1", "node": 3009, "naklon": null },
-{ "label": "15/59", "node": 3010, "naklon": 0 },
-{ "label": "15/59/1", "node": 3538, "naklon": 0 },
-{ "label": "15/59/2", "node": 4145, "naklon": 0 },
-{ "label": "15/60", "node": 2713, "naklon": 0 },
-{ "label": "15/61", "node": 2789, "naklon": 0 },
-{ "label": "15/62", "node": 2736, "naklon": 0 },
-{ "label": "15/63", "node": 2739, "naklon": 0 },
-{ "label": "15/64", "node": 4346, "naklon": 0 },
-{ "label": "15/65", "node": 2731, "naklon": 0 },
-{ "label": "15/66", "node": 2818, "naklon": 0 },
-{ "label": "15/66/1", "node": 3557, "naklon": 0 },
-{ "label": "15/67", "node": 2822, "naklon": 0 },
-{ "label": "15/68", "node": 2833, "naklon": 0 },
-{ "label": "15/69", "node": 2834, "naklon": 0 },
-{ "label": "15/70", "node": 3097, "naklon": 0 },
-{ "label": "15/71", "node": 2824, "naklon": 0 },
-{ "label": "15/72", "node": 2828, "naklon": 0 },
-{ "label": "15/73", "node": 2600, "naklon": 0 },
-{ "label": "15/73/1", "node": 4314, "naklon": 0 },
-{ "label": "15/74", "node": 2832, "naklon": 0 },
-{ "label": "15/75", "node": 4360, "naklon": 0 },
-{ "label": "15/76", "node": 2846, "naklon": 0 },
-{ "label": "15/77", "node": 2584, "naklon": 0 },
-{ "label": "15/78", "node": 2843, "naklon": 0 },
-{ "label": "15/78/1", "node": 4308, "naklon": 0 },
-{ "label": "15/79", "node": 4144, "naklon": null },
-{ "label": "15/80", "node": 2844, "naklon": 0 },
-{ "label": "15/81", "node": 2842, "naklon": 0 },
-{ "label": "15/82", "node": 2838, "naklon": 0 },
-{ "label": "15/83", "node": 2837, "naklon": null },
-{ "label": "15/83/1", "node": 3555, "naklon": null },
-{ "label": "15/84", "node": 2839, "naklon": 0 },
-{ "label": "15/85", "node": 2830, "naklon": 0 },
-{ "label": "15/86", "node": 4066, "naklon": 0 },
-{ "label": "15/87", "node": 2836, "naklon": 0 },
-{ "label": "15/88", "node": 2911, "naklon": 0 },
-{ "label": "15/89", "node": 2825, "naklon": 0 },
-{ "label": "15/90", "node": 2811, "naklon": 0 },
-{ "label": "15/94", "node": 3740, "naklon": 15 },
-{ "label": "15/95", "node": 2734, "naklon": 15 },
-{ "label": "15/96", "node": 3105, "naklon": 15 },
-{ "label": "15/97", "node": 2732, "naklon": 15 },
-{ "label": "15/98", "node": 2727, "naklon": 15 },
-{ "label": "15/99", "node": 2735, "naklon": 15 },
-{ "label": "15/100", "node": 3926, "naklon": 15 },
-{ "label": "15/101", "node": 2918, "naklon": 0 },
-{ "label": "15/102", "node": 2705, "naklon": 10 },
-{ "label": "15/103", "node": 2708, "naklon": 10 },
-{ "label": "15/104", "node": 2721, "naklon": 10 },
-{ "label": "15/105", "node": 2719, "naklon": 10 },
-{ "label": "15/106", "node": 2919, "naklon": 10 },
-{ "label": "15/107", "node": 3101, "naklon": 10 },
-{ "label": "15/108", "node": 2853, "naklon": 10 },
-{ "label": "15/109", "node": 2715, "naklon": 10 },
-{ "label": "15/110", "node": 2712, "naklon": 0 },
-{ "label": "15/111", "node": 2711, "naklon": 0 },
-{ "label": "15/112", "node": 2709, "naklon": 0 },
-{ "label": "15/113", "node": 2710, "naklon": 0 },
-{ "label": "15/114", "node": 2907, "naklon": 0 },
-{ "label": "15/115", "node": 2906, "naklon": 0 },
-{ "label": "15/116", "node": 2908, "naklon": 0 },
-{ "label": "15/117", "node": 2901, "naklon": 0 },
-{ "label": "15/118", "node": 2913, "naklon": 0 },
-{ "label": "15/119", "node": 3656, "naklon": 0 },
-{ "label": "15/120", "node": 2781, "naklon": 0 },
-{ "label": "15/121", "node": 2802, "naklon": 0 },
-{ "label": "15/122", "node": 2791, "naklon": 0 },
-{ "label": "15/123", "node": 2783, "naklon": 0 },
-{ "label": "15/124", "node": 2794, "naklon": 0 },
-{ "label": "15/125", "node": 3139, "naklon": 0 },
-{ "label": "15/126", "node": 3229, "naklon": 5 },
-{ "label": "15/127", "node": 3239, "naklon": 5 },
-{ "label": "15/128", "node": 3230, "naklon": 5 },
-{ "label": "15/129", "node": 4016, "naklon": null },
-{ "label": "16/16A", "node": 3608, "naklon": 0 },
-{ "label": "16/16B", "node": 4151, "naklon": 0 },
-{ "label": "16/1", "node": 3710, "naklon": 0 },
-{ "label": "16/2", "node": 3726, "naklon": 0 },
-{ "label": "16/3", "node": 3743, "naklon": 0 },
-{ "label": "16/4", "node": 3724, "naklon": 0 },
-{ "label": "16/5", "node": 3712, "naklon": 0 },
-{ "label": "16/6", "node": 3739, "naklon": 0 },
-{ "label": "16/7", "node": 3742, "naklon": 0 },
-{ "label": "16/8", "node": 3731, "naklon": 0 },
-{ "label": "16/9", "node": 3727, "naklon": 0 },
-{ "label": "16/10", "node": 3729, "naklon": 0 },
-{ "label": "16/11", "node": 3736, "naklon": 0 },
-{ "label": "16/12", "node": 3713, "naklon": 0 },
-{ "label": "16/13", "node": 3715, "naklon": 0 },
-{ "label": "16/14", "node": 3733, "naklon": 0 },
-{ "label": "16/15", "node": 3732, "naklon": 0 },
-{ "label": "16/17", "node": 3634, "naklon": 0 },
-{ "label": "16/18", "node": 3610, "naklon": 0 },
-{ "label": "16/19", "node": 3626, "naklon": 0 },
-{ "label": "16/20", "node": 3618, "naklon": 0 },
-{ "label": "16/21", "node": 3619, "naklon": 0 },
-{ "label": "16/22", "node": 3628, "naklon": 0 },
-{ "label": "16/23", "node": 3615, "naklon": 0 },
-{ "label": "16/24", "node": 3609, "naklon": 0 },
-{ "label": "16/25", "node": 3606, "naklon": 0 },
-{ "label": "16/26", "node": 3624, "naklon": 0 },
-{ "label": "16/27", "node": 3627, "naklon": 0 },
-{ "label": "16/28", "node": 3607, "naklon": 0 },
-{ "label": "16/29", "node": 4370, "naklon": 0 },
-{ "label": "16/30", "node": 3692, "naklon": 0 },
-{ "label": "16/31", "node": 3614, "naklon": 0 },
-{ "label": "16/32", "node": 3623, "naklon": 0 },
-{ "label": "16/33", "node": 4373, "naklon": 0 },
-{ "label": "16/34", "node": 3620, "naklon": 0 },
-{ "label": "16/35", "node": 3685, "naklon": 0 },
-{ "label": "16/36", "node": 3616, "naklon": 0 },
-{ "label": "16/37", "node": 3686, "naklon": 0 },
-{ "label": "16/38", "node": 3688, "naklon": 0 },
-{ "label": "16/39", "node": 3684, "naklon": 0 },
-{ "label": "16/40", "node": 3825, "naklon": 0 },
-{ "label": "16/41", "node": 3865, "naklon": 0 },
-{ "label": "16/42", "node": 3824, "naklon": 0 },
-{ "label": "16/43", "node": 3871, "naklon": 0 },
-{ "label": "16/44", "node": 3801, "naklon": 0 },
-{ "label": "16/45", "node": 3862, "naklon": 0 },
-{ "label": "16/46", "node": 3876, "naklon": 0 },
-{ "label": "16/47", "node": 3861, "naklon": 0 },
-{ "label": "16/48", "node": 4215, "naklon": 0 },
-{ "label": "16/49", "node": 3605, "naklon": 10 },
-{ "label": "16/50", "node": 3603, "naklon": 10 },
-{ "label": "16/51", "node": 3592, "naklon": 10 },
-{ "label": "16/52", "node": 3598, "naklon": 10 },
-{ "label": "16/53", "node": 3594, "naklon": 10 },
-{ "label": "16/54", "node": 3593, "naklon": 10 },
-{ "label": "16/55", "node": 3630, "naklon": 10 },
-{ "label": "16/56", "node": 3763, "naklon": 10 },
-{ "label": "16/57", "node": 3746, "naklon": 10 },
-{ "label": "16/58", "node": 3699, "naklon": 0 },
-{ "label": "16/59", "node": 3698, "naklon": 0 },
-{ "label": "16/60", "node": 3709, "naklon": null },
-{ "label": "16/61", "node": 3708, "naklon": 0 },
-{ "label": "16/62", "node": 3703, "naklon": null },
-{ "label": "16/63", "node": 3700, "naklon": 0 },
-{ "label": "16/64", "node": 3701, "naklon": null },
-{ "label": "16/65", "node": 3704, "naklon": 0 },
-{ "label": "16/66", "node": 3707, "naklon": null },
-{ "label": "16/67", "node": 3810, "naklon": 0 },
-{ "label": "16/68", "node": 4208, "naklon": null },
-{ "label": "16/69", "node": 3867, "naklon": 0 },
-{ "label": "16/70", "node": 4372, "naklon": null },
-{ "label": "16/71", "node": 3881, "naklon": 0 },
-{ "label": "16/72", "node": 4204, "naklon": null },
-{ "label": "16/73", "node": 3869, "naklon": 0 },
-{ "label": "16/74", "node": 4202, "naklon": null },
-{ "label": "16/75", "node": 3830, "naklon": 0 },
-{ "label": "16/76", "node": 3870, "naklon": null },
-{ "label": "16/77", "node": 3964, "naklon": 0 },
-{ "label": "16/78", "node": 3849, "naklon": 0 },
-{ "label": "16/79", "node": 3694, "naklon": null },
-{ "label": "16/80", "node": 3717, "naklon": 0 },
-{ "label": "16/81", "node": 3877, "naklon": null },
-{ "label": "16/82", "node": 3755, "naklon": 0 },
-{ "label": "16/83", "node": 3725, "naklon": null },
-{ "label": "16/84", "node": 3716, "naklon": 0 },
-{ "label": "16/85", "node": 3696, "naklon": null },
-{ "label": "16/86", "node": 3702, "naklon": 0 },
-{ "label": "16/87", "node": 3706, "naklon": null },
-{ "label": "16/88", "node": 3850, "naklon": 0 },
-{ "label": "16/89", "node": 3848, "naklon": null },
-{ "label": "16/90", "node": 3737, "naklon": null },
-{ "label": "16/91", "node": 3705, "naklon": 0 },
-{ "label": "16/92", "node": 3723, "naklon": null },
-{ "label": "16/93", "node": 3842, "naklon": 0 },
-{ "label": "16/94", "node": 3735, "naklon": null },
-{ "label": "16/95", "node": 3719, "naklon": 0 },
-{ "label": "16/96", "node": 3697, "naklon": 0 },
-{ "label": "16/97", "node": 3711, "naklon": 0 },
-{ "label": "16/98", "node": 4107, "naklon": null },
-{ "label": "16/99", "node": 4112, "naklon": 5 },
-{ "label": "16/100", "node": 4106, "naklon": 5 },
-{ "label": "16/101", "node": 4111, "naklon": 5 },
-{ "label": "16/102", "node": 4091, "naklon": null },
-{ "label": "16/103", "node": 4104, "naklon": 5 },
-{ "label": "16/104", "node": 4094, "naklon": null },
-{ "label": "16/105", "node": 4089, "naklon": 5 },
-{ "label": "16/106", "node": 4095, "naklon": null },
-{ "label": "16/107", "node": 4102, "naklon": 5 },
-{ "label": "16/108", "node": 4105, "naklon": null },
-{ "label": "16/109", "node": 3859, "naklon": null },
-{ "label": "16/110", "node": 4090, "naklon": 5 },
-{ "label": "16/111", "node": 4110, "naklon": null },
-{ "label": "16/112", "node": 4097, "naklon": 5 },
-{ "label": "16/113", "node": 4099, "naklon": null },
-{ "label": "16/114", "node": 4096, "naklon": null },
-{ "label": "16/115", "node": 4101, "naklon": 5 },
-{ "label": "16/116", "node": 4109, "naklon": null },
-{ "label": "16/117", "node": 4092, "naklon": 5 },
-{ "label": "16/118", "node": 3631, "naklon": null },
-{ "label": "16/119", "node": 3632, "naklon": 0 },
-{ "label": "16/120", "node": 3641, "naklon": null },
-{ "label": "16/121", "node": 3638, "naklon": 0 },
-{ "label": "16/122", "node": 3637, "naklon": null },
-{ "label": "16/123", "node": 4142, "naklon": null },
-{ "label": "16/124", "node": 4147, "naklon": 5 },
-{ "label": "16/125", "node": 4139, "naklon": 5 },
-{ "label": "20/30A", "node": 3172, "naklon": 2 },
-{ "label": "20/30B", "node": 3164, "naklon": 2 },
-{ "label": "20/1", "node": 3247, "naklon": 10 },
-{ "label": "20/2", "node": 3296, "naklon": 10 },
-{ "label": "20/3", "node": 3246, "naklon": 10 },
-{ "label": "20/4", "node": 3270, "naklon": 10 },
-{ "label": "20/5", "node": 3294, "naklon": 10 },
-{ "label": "20/6", "node": 3298, "naklon": 10 },
-{ "label": "20/7", "node": 3297, "naklon": 10 },
-{ "label": "20/8", "node": 3293, "naklon": 10 },
-{ "label": "20/9", "node": 3299, "naklon": 10 },
-{ "label": "20/10", "node": 3295, "naklon": 10 },
-{ "label": "20/11", "node": 3244, "naklon": 10 },
-{ "label": "20/12", "node": 3249, "naklon": 10 },
-{ "label": "20/13", "node": 3268, "naklon": 10 },
-{ "label": "20/14", "node": 3245, "naklon": 10 },
-{ "label": "20/15", "node": 3278, "naklon": 10 },
-{ "label": "20/16", "node": 3280, "naklon": 10 },
-{ "label": "20/17", "node": 3292, "naklon": 10 },
-{ "label": "20/18", "node": 3287, "naklon": 10 },
-{ "label": "20/19", "node": 3282, "naklon": 10 },
-{ "label": "20/20", "node": 3273, "naklon": 0 },
-{ "label": "20/21", "node": 3157, "naklon": 0 },
-{ "label": "20/22", "node": 3283, "naklon": 0 },
-{ "label": "20/23", "node": 3159, "naklon": 0 },
-{ "label": "20/24", "node": 3289, "naklon": 0 },
-{ "label": "20/25", "node": 3163, "naklon": 0 },
-{ "label": "20/26", "node": 3126, "naklon": 0 },
-{ "label": "20/27", "node": 3171, "naklon": 0 },
-{ "label": "20/28", "node": 3162, "naklon": 0 },
-{ "label": "20/29", "node": 3279, "naklon": 10 },
-{ "label": "20/31", "node": 3173, "naklon": 0 },
-{ "label": "20/32", "node": 3127, "naklon": 0 },
-{ "label": "20/33", "node": 3131, "naklon": 0 },
-{ "label": "20/34", "node": 3129, "naklon": 0 },
-{ "label": "20/35", "node": 3276, "naklon": 2 },
-{ "label": "20/36", "node": 3290, "naklon": 2 },
-{ "label": "20/37", "node": 3132, "naklon": 0 },
-{ "label": "20/38", "node": 3138, "naklon": 0 },
-{ "label": "20/39", "node": 3272, "naklon": 0 },
-{ "label": "20/40", "node": 3291, "naklon": 0 },
-{ "label": "20/41", "node": 3277, "naklon": 10 },
-{ "label": "20/42", "node": 3286, "naklon": 10 },
-{ "label": "20/43", "node": 3281, "naklon": 10 },
-{ "label": "20/44", "node": 3288, "naklon": 10 },
-{ "label": "20/45", "node": 3284, "naklon": 10 },
-{ "label": "20/46", "node": 3167, "naklon": 10 },
-{ "label": "20/47", "node": 3872, "naklon": 0 },
-{ "label": "20/48", "node": 3124, "naklon": 0 },
-{ "label": "20/49", "node": 3133, "naklon": 0 },
-{ "label": "20/50", "node": 3158, "naklon": 0 },
-{ "label": "20/51", "node": 3169, "naklon": 0 },
-{ "label": "20/52", "node": 3146, "naklon": 0 },
-{ "label": "20/53", "node": 3160, "naklon": 0 },
-{ "label": "20/54", "node": 3248, "naklon": 0 },
-{ "label": "20/55", "node": 3156, "naklon": 0 },
-{ "label": "20/56", "node": 3161, "naklon": 0 },
-{ "label": "20/57", "node": 3170, "naklon": 0 },
-{ "label": "20/58", "node": 3168, "naklon": 0 },
-{ "label": "20/59", "node": 3125, "naklon": 0 },
-{ "label": "20/60", "node": 3166, "naklon": 0 },
-{ "label": "20/61", "node": 3130, "naklon": 0 },
-{ "label": "20/62", "node": 3563, "naklon": 0 },
-{ "label": "20/63", "node": 3550, "naklon": null },
-{ "label": "20/67", "node": 3269, "naklon": 0 },
-{ "label": "21/1", "node": 2921, "naklon": 0 },
-{ "label": "21/2", "node": 2707, "naklon": 0 },
-{ "label": "21/3", "node": 2723, "naklon": 0 },
-{ "label": "21/4", "node": 2716, "naklon": 0 },
-{ "label": "21/5", "node": 2717, "naklon": 0 },
-{ "label": "21/6", "node": 2720, "naklon": 0 },
-{ "label": "21/7", "node": 2722, "naklon": 0 },
-{ "label": "21/8", "node": 2718, "naklon": 0 },
-{ "label": "21/9", "node": 2724, "naklon": 0 },
-{ "label": "21/10", "node": 2742, "naklon": 0 },
-{ "label": "21/11", "node": 2743, "naklon": 0 },
-{ "label": "21/12", "node": 2733, "naklon": 0 },
-{ "label": "21/14", "node": 2903, "naklon": 0 },
-{ "label": "21/15", "node": 2917, "naklon": 0 },
-{ "label": "21/16", "node": 2897, "naklon": 0 },
-{ "label": "21/17", "node": 2914, "naklon": 0 },
-{ "label": "21/18", "node": 2898, "naklon": 0 },
-{ "label": "21/19", "node": 2773, "naklon": 0 },
-{ "label": "21/20", "node": 2895, "naklon": 0 },
-{ "label": "21/21", "node": 2896, "naklon": 0 },
-{ "label": "21/22", "node": 2771, "naklon": 0 },
-{ "label": "21/23", "node": 2772, "naklon": 0 },
-{ "label": "21/24", "node": 2793, "naklon": 0 },
-{ "label": "21/25", "node": 2902, "naklon": 0 },
-{ "label": "21/26", "node": 2910, "naklon": 0 },
-{ "label": "21/27", "node": 2909, "naklon": 0 },
-{ "label": "21/28", "node": 2920, "naklon": 0 },
-{ "label": "21/29", "node": 2916, "naklon": 0 },
-{ "label": "21/30", "node": 2904, "naklon": 0 },
-{ "label": "21/31", "node": 2915, "naklon": 0 },
-{ "label": "21/32", "node": 2905, "naklon": 0 },
-{ "label": "21/33", "node": 2900, "naklon": 0 },
-{ "label": "21/34", "node": 2899, "naklon": 0 },
-{ "label": "21/36", "node": 2741, "naklon": 0 },
-{ "label": "21/37", "node": 2714, "naklon": 0 },
-{ "label": "21/38", "node": 2701, "naklon": 0 },
-{ "label": "21/39", "node": 2703, "naklon": 0 },
-{ "label": "21/40", "node": 2704, "naklon": 0 },
-{ "label": "21/41", "node": 2702, "naklon": 0 },
-{ "label": "21/42", "node": 2706, "naklon": 0 },
-{ "label": "21/43", "node": 2776, "naklon": 0 },
-{ "label": "21/44", "node": 2770, "naklon": 0 },
-{ "label": "21/45", "node": 2786, "naklon": 0 },
-{ "label": "21/46", "node": 2779, "naklon": 0 },
-{ "label": "21/47", "node": 2782, "naklon": 0 },
-{ "label": "21/48", "node": 2785, "naklon": 0 },
-{ "label": "21/49", "node": 2769, "naklon": 0 },
-{ "label": "21/50", "node": 3354, "naklon": 0 },
-{ "label": "21/51", "node": 2778, "naklon": 0 },
-{ "label": "21/52", "node": 2775, "naklon": 0 },
-{ "label": "21/53", "node": 2780, "naklon": 0 },
-{ "label": "21/54", "node": 2790, "naklon": 0 },
-{ "label": "21/55", "node": 2792, "naklon": 0 },
-{ "label": "21/56", "node": 2774, "naklon": 0 },
-{ "label": "22/1", "node": 2630, "naklon": 0 },
-{ "label": "22/2", "node": 2631, "naklon": 0 },
-{ "label": "22/3", "node": 2632, "naklon": 0 },
-{ "label": "22/4", "node": 2633, "naklon": 0 },
-{ "label": "22/5", "node": 2634, "naklon": 0 },
-{ "label": "22/6", "node": 2636, "naklon": 0 },
-{ "label": "22/7", "node": 4367, "naklon": 0 },
-{ "label": "22/8", "node": 2637, "naklon": 0 },
-{ "label": "22/9", "node": 2638, "naklon": 0 },
-{ "label": "22/10", "node": 2639, "naklon": 0 },
-{ "label": "22/11", "node": 2640, "naklon": 0 },
-{ "label": "22/12", "node": 2641, "naklon": 0 },
-{ "label": "22/13", "node": 2642, "naklon": 0 },
-{ "label": "22/14", "node": 2643, "naklon": 0 },
-{ "label": "22/15", "node": 2644, "naklon": 0 },
-{ "label": "22/16", "node": 2645, "naklon": 0 },
-{ "label": "22/17", "node": 2646, "naklon": 0 },
-{ "label": "22/18", "node": 2647, "naklon": 0 },
-{ "label": "22/19", "node": 2648, "naklon": 0 },
-{ "label": "22/20", "node": 2649, "naklon": 0 },
-{ "label": "22/21", "node": 2650, "naklon": 0 },
-{ "label": "22/22", "node": 2651, "naklon": 0 },
-{ "label": "22/23", "node": 4103, "naklon": 0 },
-{ "label": "22/24", "node": 2653, "naklon": 0 },
-{ "label": "22/25", "node": 2654, "naklon": 0 },
-{ "label": "22/26", "node": 2655, "naklon": 0 },
-{ "label": "22/27", "node": 2656, "naklon": 0 },
-{ "label": "22/28", "node": 2657, "naklon": 0 },
-{ "label": "22/29", "node": 2658, "naklon": 0 },
-{ "label": "22/30", "node": 2659, "naklon": 0 },
-{ "label": "22/31", "node": 2660, "naklon": 0 },
-{ "label": "22/32", "node": 2661, "naklon": 0 },
-{ "label": "22/32/1", "node": 3015, "naklon": 0 },
-{ "label": "22/33", "node": 2662, "naklon": 0 },
-{ "label": "22/34", "node": 2663, "naklon": 0 },
-{ "label": "22/35", "node": 2664, "naklon": 0 },
-{ "label": "22/36", "node": 2665, "naklon": 0 },
-{ "label": "22/37", "node": 2666, "naklon": 0 },
-{ "label": "22/38", "node": 2667, "naklon": 0 },
-{ "label": "22/39", "node": 2668, "naklon": 0 },
-{ "label": "22/40", "node": 2669, "naklon": null },
-{ "label": "22/41", "node": 2670, "naklon": null },
-{ "label": "22/42", "node": 2671, "naklon": null },
-{ "label": "23/9A", "node": 3087, "naklon": 10 },
-{ "label": "23/9B", "node": 3090, "naklon": 10 },
-{ "label": "23/1", "node": 3075, "naklon": 0 },
-{ "label": "23/2", "node": 3089, "naklon": 0 },
-{ "label": "23/3", "node": 3088, "naklon": 0 },
-{ "label": "23/4", "node": 3228, "naklon": 10 },
-{ "label": "23/5", "node": 2751, "naklon": 10 },
-{ "label": "23/6", "node": 3243, "naklon": 10 },
-{ "label": "23/7", "node": 4349, "naklon": 10 },
-{ "label": "23/8", "node": 3102, "naklon": 10 },
-{ "label": "23/10", "node": 3099, "naklon": 10 },
-{ "label": "23/11", "node": 3103, "naklon": 10 },
-{ "label": "23/12", "node": 3093, "naklon": 10 },
-{ "label": "23/13", "node": 3098, "naklon": 10 },
-{ "label": "23/14", "node": 3092, "naklon": 10 },
-{ "label": "23/15", "node": 3233, "naklon": 0 },
-{ "label": "23/16", "node": 3095, "naklon": 0 },
-{ "label": "23/17", "node": 4074, "naklon": 0 },
-{ "label": "23/18", "node": 2729, "naklon": 0 },
-{ "label": "23/19", "node": 3234, "naklon": 0 },
-{ "label": "23/20", "node": 3094, "naklon": 0 },
-{ "label": "23/21", "node": 2817, "naklon": 0 },
-{ "label": "23/22", "node": 3226, "naklon": 0 },
-{ "label": "23/23", "node": 3225, "naklon": 0 },
-{ "label": "23/24", "node": 3237, "naklon": 0 },
-{ "label": "23/25", "node": 4250, "naklon": 0 },
-{ "label": "23/26", "node": 3059, "naklon": 10 },
-{ "label": "23/27", "node": 3238, "naklon": 10 },
-{ "label": "23/28", "node": 3242, "naklon": 10 },
-{ "label": "23/29", "node": 3236, "naklon": 10 },
-{ "label": "23/30", "node": 3112, "naklon": 10 },
-{ "label": "23/31", "node": 3224, "naklon": 0 },
-{ "label": "23/32", "node": 4298, "naklon": 10 },
-{ "label": "23/33", "node": 4150, "naklon": 10 },
-{ "label": "23/34", "node": 3091, "naklon": 10 },
-{ "label": "25/1", "node": 3771, "naklon": 5 },
-{ "label": "25/2", "node": 3777, "naklon": 5 },
-{ "label": "25/3", "node": 3749, "naklon": 5 },
-{ "label": "25/4", "node": 3769, "naklon": 5 },
-{ "label": "25/5", "node": 3765, "naklon": 5 },
-{ "label": "25/6", "node": 3785, "naklon": 5 },
-{ "label": "25/7", "node": 3761, "naklon": 5 },
-{ "label": "25/8", "node": 3758, "naklon": 5 },
-{ "label": "25/9", "node": 3766, "naklon": 5 },
-{ "label": "25/10", "node": 3779, "naklon": 5 },
-{ "label": "25/11", "node": 3899, "naklon": 10 },
-{ "label": "25/12", "node": 3922, "naklon": 10 },
-{ "label": "25/13", "node": 3912, "naklon": 10 },
-{ "label": "25/14", "node": 3933, "naklon": 10 },
-{ "label": "25/15", "node": 3921, "naklon": 10 },
-{ "label": "25/16", "node": 4300, "naklon": 10 },
-{ "label": "25/17", "node": 3927, "naklon": 10 },
-{ "label": "25/18", "node": 3212, "naklon": 10 },
-{ "label": "25/19", "node": 3208, "naklon": 10 },
-{ "label": "25/20", "node": 3207, "naklon": 10 },
-{ "label": "25/21", "node": 4294, "naklon": 10 },
-{ "label": "25/22", "node": 3209, "naklon": 10 },
-{ "label": "25/23", "node": 3745, "naklon": 10 },
-{ "label": "25/24", "node": 3762, "naklon": 10 },
-{ "label": "25/25", "node": 3215, "naklon": 10 },
-{ "label": "25/26", "node": 3210, "naklon": 10 },
-{ "label": "25/27", "node": 3211, "naklon": 10 },
-{ "label": "25/28", "node": 3206, "naklon": 10 },
-{ "label": "25/29", "node": 3918, "naklon": 5 },
-{ "label": "25/30", "node": 3928, "naklon": 5 },
-{ "label": "25/31", "node": 3917, "naklon": 5 },
-{ "label": "25/32", "node": 4029, "naklon": 0 },
-{ "label": "25/33", "node": 4038, "naklon": 0 },
-{ "label": "25/34", "node": 4022, "naklon": 0 },
-{ "label": "25/35", "node": 3937, "naklon": 0 },
-{ "label": "25/36", "node": 3190, "naklon": 0 },
-{ "label": "25/37", "node": 3835, "naklon": 0 },
-{ "label": "25/38", "node": 3201, "naklon": 0 },
-{ "label": "25/39", "node": 3193, "naklon": 0 },
-{ "label": "25/40", "node": 3191, "naklon": 0 },
-{ "label": "25/41", "node": 3203, "naklon": 0 },
-{ "label": "25/42", "node": 4301, "naklon": 0 },
-{ "label": "25/43", "node": 3223, "naklon": 0 },
-{ "label": "25/44", "node": 3202, "naklon": 0 },
-{ "label": "25/45", "node": 3205, "naklon": 0 },
-{ "label": "25/46", "node": 3194, "naklon": 0 },
-{ "label": "25/47", "node": 3198, "naklon": 0 },
-{ "label": "25/48", "node": 3204, "naklon": 0 },
-{ "label": "25/49", "node": 3200, "naklon": 0 },
-{ "label": "25/50", "node": 3216, "naklon": 0 },
-{ "label": "25/51", "node": 3932, "naklon": 5 },
-{ "label": "25/52", "node": 3923, "naklon": 5 },
-{ "label": "25/53", "node": 3913, "naklon": 5 },
-{ "label": "25/54", "node": 3900, "naklon": 5 },
-{ "label": "25/55", "node": 4189, "naklon": 10 },
-{ "label": "25/56", "node": 4191, "naklon": 10 },
-{ "label": "25/57", "node": 3790, "naklon": 10 },
-{ "label": "25/58", "node": 4190, "naklon": 10 },
-{ "label": "25/59", "node": 4302, "naklon": 0 },
-{ "label": "25/60", "node": 4351, "naklon": 0 },
-{ "label": "25/61", "node": 4075, "naklon": 0 },
-{ "label": "25/62", "node": 4071, "naklon": 0 },
-{ "label": "25/63", "node": 3784, "naklon": 0 },
-{ "label": "25/64", "node": 4065, "naklon": 0 },
-{ "label": "25/65", "node": 4297, "naklon": 0 },
-{ "label": "25/66", "node": 4295, "naklon": 0 },
-{ "label": "25/67", "node": 4299, "naklon": 0 },
-{ "label": "25/68", "node": 3772, "naklon": 0 },
-{ "label": "25/69", "node": 3941, "naklon": 0 },
-{ "label": "25/70", "node": 3782, "naklon": 0 },
-{ "label": "25/71", "node": 4068, "naklon": 0 },
-{ "label": "25/72", "node": 4073, "naklon": 0 },
-{ "label": "25/73", "node": 3901, "naklon": 5 },
-{ "label": "25/74", "node": 4296, "naklon": 5 },
-{ "label": "25/75", "node": 3910, "naklon": 5 },
-{ "label": "25/76", "node": 4293, "naklon": 5 },
-{ "label": "25/77", "node": 3919, "naklon": 5 },
-{ "label": "25/78", "node": 3924, "naklon": 5 },
-{ "label": "25/79", "node": 3909, "naklon": 5 },
-{ "label": "25/80", "node": 3896, "naklon": 5 },
-{ "label": "25/81", "node": 3911, "naklon": 5 },
-{ "label": "25/82", "node": 2819, "naklon": 15 },
-{ "label": "25/83", "node": 3776, "naklon": 15 },
-{ "label": "25/84", "node": 3752, "naklon": 15 },
-{ "label": "25/85", "node": 4353, "naklon": 15 },
-{ "label": "25/86", "node": 3791, "naklon": 0 },
-{ "label": "25/87", "node": 3770, "naklon": 0 },
-{ "label": "25/88", "node": 3760, "naklon": 0 },
-{ "label": "25/89", "node": 3115, "naklon": 0 },
-{ "label": "25/90", "node": 3738, "naklon": 0 },
-{ "label": "25/91", "node": 3748, "naklon": 0 },
-{ "label": "25/92", "node": 3753, "naklon": 0 },
-{ "label": "25/93", "node": 3775, "naklon": 0 },
-{ "label": "25/94", "node": 3778, "naklon": 5 },
-{ "label": "25/95", "node": 4078, "naklon": 5 },
-{ "label": "25/96", "node": 4088, "naklon": 5 },
-{ "label": "25/97", "node": 3856, "naklon": 5 },
-{ "label": "25/98", "node": 4084, "naklon": 5 },
-{ "label": "25/99", "node": 4069, "naklon": 5 },
-{ "label": "25/100", "node": 4188, "naklon": 5 },
-{ "label": "25/101", "node": 4064, "naklon": 5 },
-{ "label": "25/102", "node": 3792, "naklon": 5 },
-{ "label": "25/103", "node": 3780, "naklon": 5 },
-{ "label": "25/104", "node": 4034, "naklon": 5 },
-{ "label": "25/105", "node": 4072, "naklon": 5 },
-{ "label": "25/106", "node": 3884, "naklon": 5 },
-{ "label": "25/107", "node": 3793, "naklon": 5 },
-{ "label": "25/108", "node": 3863, "naklon": 5 },
-{ "label": "25/109", "node": 3855, "naklon": 5 },
-{ "label": "33/1", "node": 3846, "naklon": 0 },
-{ "label": "33/2", "node": 3943, "naklon": 0 },
-{ "label": "33/3", "node": 3903, "naklon": 0 },
-{ "label": "33/4", "node": 3982, "naklon": 0 },
-{ "label": "33/5", "node": 3879, "naklon": 0 },
-{ "label": "33/6", "node": 3887, "naklon": 0 },
-{ "label": "33/7", "node": 3920, "naklon": 5 },
-{ "label": "33/8", "node": 3942, "naklon": 5 },
-{ "label": "33/9", "node": 3829, "naklon": null },
-{ "label": "34/79A", "node": 3452, "naklon": 6 },
-{ "label": "34/79B", "node": 3460, "naklon": 6 },
-{ "label": "34/90A", "node": 3443, "naklon": 6 },
-{ "label": "34/90B", "node": 3445, "naklon": 6 },
-{ "label": "34/90C", "node": 3457, "naklon": 6 },
-{ "label": "34/97A", "node": 3461, "naklon": 6 },
-{ "label": "34/97B", "node": 3463, "naklon": 6 },
-{ "label": "34/98A", "node": 3426, "naklon": 6 },
-{ "label": "34/98B", "node": 3444, "naklon": 6 },
-{ "label": "34/99A", "node": 3453, "naklon": 6 },
-{ "label": "34/99B", "node": 3455, "naklon": 6 },
-{ "label": "34/1", "node": 4009, "naklon": 0 },
-{ "label": "34/2", "node": 3602, "naklon": 0 },
-{ "label": "34/3", "node": 3441, "naklon": 0 },
-{ "label": "34/4", "node": 3464, "naklon": 0 },
-{ "label": "34/5", "node": 3883, "naklon": 0 },
-{ "label": "34/6", "node": 4098, "naklon": 0 },
-{ "label": "34/7", "node": 4003, "naklon": 0 },
-{ "label": "34/8", "node": 4004, "naklon": 0 },
-{ "label": "34/9", "node": 3888, "naklon": 0 },
-{ "label": "34/10", "node": 3997, "naklon": 0 },
-{ "label": "34/11", "node": 4006, "naklon": 0 },
-{ "label": "34/12", "node": 4000, "naklon": 0 },
-{ "label": "34/13", "node": 4011, "naklon": 0 },
-{ "label": "34/14", "node": 3999, "naklon": 0 },
-{ "label": "34/15", "node": 3981, "naklon": 0 },
-{ "label": "34/16", "node": 3988, "naklon": 0 },
-{ "label": "34/17", "node": 3986, "naklon": 0 },
-{ "label": "34/18", "node": 3998, "naklon": 0 },
-{ "label": "34/19", "node": 3983, "naklon": 0 },
-{ "label": "34/20", "node": 4005, "naklon": 0 },
-{ "label": "34/21", "node": 4001, "naklon": 0 },
-{ "label": "34/22", "node": 4008, "naklon": 0 },
-{ "label": "34/23", "node": 4002, "naklon": 0 },
-{ "label": "34/24", "node": 3996, "naklon": 0 },
-{ "label": "34/25", "node": 4007, "naklon": 0 },
-{ "label": "34/26", "node": 4113, "naklon": 15 },
-{ "label": "34/27", "node": 3595, "naklon": 5 },
-{ "label": "34/28", "node": 3599, "naklon": 5 },
-{ "label": "34/29", "node": 3601, "naklon": 5 },
-{ "label": "34/30", "node": 4205, "naklon": 0 },
-{ "label": "34/31", "node": 3987, "naklon": null },
-{ "label": "34/32", "node": 4214, "naklon": 0 },
-{ "label": "34/33", "node": 4226, "naklon": 0 },
-{ "label": "34/34", "node": 4209, "naklon": 0 },
-{ "label": "34/35", "node": 4201, "naklon": 0 },
-{ "label": "34/36", "node": 3440, "naklon": 0 },
-{ "label": "34/37", "node": 3465, "naklon": 0 },
-{ "label": "34/38", "node": 3446, "naklon": 0 },
-{ "label": "34/39", "node": 4039, "naklon": 5 },
-{ "label": "34/40", "node": 4057, "naklon": 5 },
-{ "label": "34/41", "node": 3985, "naklon": 0 },
-{ "label": "34/42", "node": 3882, "naklon": 0 },
-{ "label": "34/43", "node": 4040, "naklon": 5 },
-{ "label": "34/44", "node": 3231, "naklon": 0 },
-{ "label": "34/45", "node": 3227, "naklon": 0 },
-{ "label": "34/46", "node": 3431, "naklon": 0 },
-{ "label": "34/47", "node": 4013, "naklon": 0 },
-{ "label": "34/48", "node": 4045, "naklon": 0 },
-{ "label": "34/49", "node": 3949, "naklon": 0 },
-{ "label": "34/50", "node": 3953, "naklon": 0 },
-{ "label": "34/51", "node": 3952, "naklon": 0 },
-{ "label": "34/52", "node": 3995, "naklon": 0 },
-{ "label": "34/53", "node": 3992, "naklon": 0 },
-{ "label": "34/54", "node": 4198, "naklon": 0 },
-{ "label": "34/55", "node": 3935, "naklon": 0 },
-{ "label": "34/56", "node": 4050, "naklon": 0 },
-{ "label": "34/57", "node": 4049, "naklon": 0 },
-{ "label": "34/58", "node": 4054, "naklon": 0 },
-{ "label": "34/59", "node": 3663, "naklon": 6 },
-{ "label": "34/60", "node": 3661, "naklon": 6 },
-{ "label": "34/61", "node": 3664, "naklon": 6 },
-{ "label": "34/62", "node": 3660, "naklon": 6 },
-{ "label": "34/63", "node": 3662, "naklon": 6 },
-{ "label": "34/65", "node": 3665, "naklon": 6 },
-{ "label": "34/66", "node": 3667, "naklon": 6 },
-{ "label": "34/67", "node": 3675, "naklon": 6 },
-{ "label": "34/68", "node": 3666, "naklon": 6 },
-{ "label": "34/69", "node": 3652, "naklon": 6 },
-{ "label": "34/70", "node": 3458, "naklon": 6 },
-{ "label": "34/70/1", "node": 4425, "naklon": 6 },
-{ "label": "34/71", "node": 3459, "naklon": 6 },
-{ "label": "34/72", "node": 3435, "naklon": 6 },
-{ "label": "34/73", "node": 3448, "naklon": 6 },
-{ "label": "34/74", "node": 3451, "naklon": 6 },
-{ "label": "34/75", "node": 3442, "naklon": 6 },
-{ "label": "34/76", "node": 3449, "naklon": 6 },
-{ "label": "34/77", "node": 3450, "naklon": 6 },
-{ "label": "34/78", "node": 3433, "naklon": 6 },
-{ "label": "34/80", "node": 3432, "naklon": 12 },
-{ "label": "34/81", "node": 3470, "naklon": 12 },
-{ "label": "34/82", "node": 3438, "naklon": 12 },
-{ "label": "34/83", "node": 3439, "naklon": 12 },
-{ "label": "34/84", "node": 4028, "naklon": 5 },
-{ "label": "34/85", "node": 3596, "naklon": 5 },
-{ "label": "34/86", "node": 4021, "naklon": 5 },
-{ "label": "34/87", "node": 3437, "naklon": 12 },
-{ "label": "34/88", "node": 3428, "naklon": 12 },
-{ "label": "34/89", "node": 3430, "naklon": 12 },
-{ "label": "34/91", "node": 3454, "naklon": 6 },
-{ "label": "34/92", "node": 3492, "naklon": 6 },
-{ "label": "34/93", "node": 3462, "naklon": 6 },
-{ "label": "34/94", "node": 3427, "naklon": 6 },
-{ "label": "34/95", "node": 3434, "naklon": 6 },
-{ "label": "34/96", "node": 3456, "naklon": 6 },
-{ "label": "34/98/1", "node": 4307, "naklon": 6 },
-{ "label": "35/1", "node": 3968, "naklon": 0 },
-{ "label": "35/2", "node": 3969, "naklon": 0 },
-{ "label": "35/3", "node": 3947, "naklon": 0 },
-{ "label": "35/4", "node": 3979, "naklon": 0 },
-{ "label": "35/5", "node": 3959, "naklon": 0 },
-{ "label": "35/6", "node": 3948, "naklon": 0 },
-{ "label": "35/7", "node": 3961, "naklon": 0 },
-{ "label": "35/8", "node": 3956, "naklon": 0 },
-{ "label": "35/9", "node": 3604, "naklon": 0 },
-{ "label": "35/10", "node": 3944, "naklon": 0 },
-{ "label": "35/11", "node": 3960, "naklon": 0 },
-{ "label": "35/12", "node": 3958, "naklon": 0 },
-{ "label": "35/13", "node": 4036, "naklon": 5 },
-{ "label": "35/18", "node": 3893, "naklon": 5 },
-{ "label": "35/19", "node": 4108, "naklon": 5 },
-{ "label": "35/20", "node": 4017, "naklon": 5 },
-{ "label": "35/21", "node": 3963, "naklon": 0 },
-{ "label": "35/22", "node": 3658, "naklon": 0 },
-{ "label": "35/23", "node": 3975, "naklon": 0 },
-{ "label": "35/24", "node": 3980, "naklon": 0 },
-{ "label": "35/25", "node": 4012, "naklon": 0 },
-{ "label": "35/26", "node": 3655, "naklon": 0 },
-{ "label": "35/27", "node": 3962, "naklon": 0 },
-{ "label": "35/28", "node": 3945, "naklon": 0 },
-{ "label": "35/29", "node": 3569, "naklon": 0 },
-{ "label": "35/30", "node": 3429, "naklon": 0 },
-{ "label": "35/31", "node": 3657, "naklon": 0 },
-{ "label": "35/32", "node": 3646, "naklon": 0 },
-{ "label": "35/33", "node": 3622, "naklon": 0 },
-{ "label": "35/34", "node": 3612, "naklon": 0 },
-{ "label": "35/35", "node": 3955, "naklon": 0 },
-{ "label": "35/37", "node": 3878, "naklon": 0 },
-{ "label": "35/38", "node": 3965, "naklon": 0 },
-{ "label": "35/39", "node": 3970, "naklon": 0 },
-{ "label": "35/40", "node": 3611, "naklon": 0 },
-{ "label": "35/41", "node": 2635, "naklon": 0 },
-{ "label": "35/42", "node": 3978, "naklon": 0 },
-{ "label": "35/43", "node": 4213, "naklon": 0 },
-{ "label": "35/44", "node": 3984, "naklon": 0 },
-{ "label": "35/45", "node": 4218, "naklon": 0 },
-{ "label": "35/46", "node": 3973, "naklon": 0 },
-{ "label": "35/47", "node": 3974, "naklon": 0 },
-{ "label": "35/48", "node": 3759, "naklon": 0 },
-{ "label": "35/49", "node": 3844, "naklon": 0 },
-{ "label": "35/50", "node": 3804, "naklon": 0 },
-{ "label": "35/51", "node": 3831, "naklon": 0 },
-{ "label": "35/52", "node": 3643, "naklon": 0 },
-{ "label": "35/53", "node": 3966, "naklon": 0 },
-{ "label": "35/54", "node": 3971, "naklon": 0 },
-{ "label": "35/55", "node": 3650, "naklon": 6 },
-{ "label": "35/56", "node": 3651, "naklon": 6 },
-{ "label": "35/57", "node": 3669, "naklon": 6 },
-{ "label": "35/58", "node": 3648, "naklon": 6 },
-{ "label": "35/59", "node": 3645, "naklon": 6 },
-{ "label": "35/60", "node": 3659, "naklon": 6 },
-{ "label": "35/61", "node": 3647, "naklon": 6 },
-{ "label": "35/62", "node": 3644, "naklon": 6 },
-{ "label": "35/63", "node": 3671, "naklon": 6 },
-{ "label": "35/64", "node": 3682, "naklon": 6 },
-{ "label": "35/65", "node": 3672, "naklon": 6 },
-{ "label": "35/66", "node": 3683, "naklon": 6 },
-{ "label": "35/67", "node": 3673, "naklon": 6 },
-{ "label": "35/68", "node": 3674, "naklon": 6 },
-{ "label": "35/69", "node": 3679, "naklon": 6 },
-{ "label": "35/70", "node": 3649, "naklon": 6 },
-{ "label": "35/71", "node": 3687, "naklon": 6 },
-{ "label": "35/72", "node": 3677, "naklon": 6 },
-{ "label": "35/73", "node": 3690, "naklon": 6 },
-{ "label": "35/74", "node": 3691, "naklon": 6 },
-{ "label": "35/75", "node": 3676, "naklon": 6 },
-{ "label": "35/76", "node": 3680, "naklon": 6 },
-{ "label": "35/77", "node": 3668, "naklon": 6 },
-{ "label": "35/78", "node": 3681, "naklon": 6 },
-{ "label": "35/79", "node": 3670, "naklon": 6 },
-{ "label": "35/80", "node": 3689, "naklon": 6 },
-{ "label": "35/81", "node": 3678, "naklon": 6 },
-{ "label": "35/82", "node": 3693, "naklon": 6 },
-{ "label": "35/83", "node": 3654, "naklon": null },
-{ "label": "36/1", "node": 4086, "naklon": 0 },
-{ "label": "36/2", "node": 4085, "naklon": 0 },
-{ "label": "36/3", "node": 4083, "naklon": 0 },
-{ "label": "36/4", "node": 4087, "naklon": 0 },
-{ "label": "36/5", "node": 4077, "naklon": 0 },
-{ "label": "36/6", "node": 4082, "naklon": 0 },
-{ "label": "36/7", "node": 4186, "naklon": 0 },
-{ "label": "36/8", "node": 4206, "naklon": 0 },
-{ "label": "36/9", "node": 4080, "naklon": 0 },
-{ "label": "36/10", "node": 4081, "naklon": 0 },
-{ "label": "36/11", "node": 4210, "naklon": 0 },
-{ "label": "36/12", "node": 4079, "naklon": 0 },
-{ "label": "36/13", "node": 4076, "naklon": 0 },
-{ "label": "36/14", "node": 3852, "naklon": 0 },
-{ "label": "36/15", "node": 2813, "naklon": 0 },
-{ "label": "36/16", "node": 4219, "naklon": 0 },
-{ "label": "37/1A", "node": 3104, "naklon": 15 },
-{ "label": "37/1B", "node": 3121, "naklon": 15 },
-{ "label": "37/2", "node": 3113, "naklon": 10 },
-{ "label": "37/3", "node": 3118, "naklon": 10 },
-{ "label": "37/4", "node": 3111, "naklon": 10 },
-{ "label": "37/5", "node": 4020, "naklon": 10 },
-{ "label": "37/6", "node": 3119, "naklon": 10 },
-{ "label": "37/7", "node": 3110, "naklon": 10 },
-{ "label": "37/8", "node": 3108, "naklon": 10 },
-{ "label": "37/12", "node": 3107, "naklon": 0 },
-{ "label": "37/13", "node": 3199, "naklon": 0 },
-{ "label": "37/14", "node": 3120, "naklon": 0 },
-{ "label": "37/15", "node": 3122, "naklon": 0 },
-{ "label": "37/16", "node": 3908, "naklon": 0 },
-{ "label": "37/17", "node": 3114, "naklon": 0 },
-{ "label": "37/18", "node": 3105, "naklon": 0 },
-{ "label": "37/19", "node": 3116, "naklon": 0 },
-{ "label": "37/20", "node": 3106, "naklon": 0 },
-{ "label": "37/21", "node": 2887, "naklon": 5 },
-{ "label": "37/22", "node": 2888, "naklon": 5 },
-{ "label": "37/23", "node": 2877, "naklon": 5 },
-{ "label": "37/24", "node": 2891, "naklon": 5 },
-{ "label": "37/25", "node": 2886, "naklon": 5 },
-{ "label": "37/26", "node": 2892, "naklon": 5 },
-{ "label": "37/27", "node": 2882, "naklon": 5 },
-{ "label": "37/28", "node": 2883, "naklon": 5 },
-{ "label": "37/29", "node": 2876, "naklon": 5 },
-{ "label": "37/30", "node": 3109, "naklon": 5 },
-{ "label": "37/31", "node": 4152, "naklon": 5 },
-{ "label": "37/32", "node": 3117, "naklon": 5 },
-{ "label": "37/33", "node": 2870, "naklon": 5 },
-{ "label": "37/34", "node": 2867, "naklon": 0 },
-{ "label": "37/35", "node": 2865, "naklon": 0 },
-{ "label": "37/36", "node": 3096, "naklon": 0 },
-{ "label": "37/37", "node": 2871, "naklon": 0 },
-{ "label": "37/38", "node": 2884, "naklon": 0 },
-{ "label": "37/39", "node": 2855, "naklon": 0 },
-{ "label": "37/40", "node": 2878, "naklon": 0 },
-{ "label": "37/41", "node": 2889, "naklon": 0 },
-{ "label": "37/42", "node": 2879, "naklon": 0 },
-{ "label": "37/43", "node": 2850, "naklon": 0 },
-{ "label": "37/44", "node": 2894, "naklon": 0 },
-{ "label": "37/45", "node": 2880, "naklon": 0 },
-{ "label": "37/46", "node": 2893, "naklon": 0 },
-{ "label": "37/47", "node": 2890, "naklon": 0 },
-{ "label": "37/48", "node": 4355, "naklon": 0 },
-{ "label": "37/49", "node": 2885, "naklon": 0 },
-{ "label": "37/50", "node": 2875, "naklon": 0 },
-{ "label": "38/30A", "node": 3486, "naklon": 5 },
-{ "label": "38/30B", "node": 3714, "naklon": 0 },
-{ "label": "38/32A", "node": 3483, "naklon": 5 },
-{ "label": "38/32B", "node": 3496, "naklon": 0 },
-{ "label": "38/35A", "node": 3487, "naklon": 5 },
-{ "label": "38/35B", "node": 3498, "naklon": 5 },
-{ "label": "38/38A", "node": 3578, "naklon": 5 },
-{ "label": "38/38B", "node": 3508, "naklon": 5 },
-{ "label": "38/59A", "node": 3787, "naklon": 5 },
-{ "label": "38/59B", "node": 3491, "naklon": 5 },
-{ "label": "38/1", "node": 3568, "naklon": null },
-{ "label": "38/2", "node": 3502, "naklon": 0 },
-{ "label": "38/3", "node": 3836, "naklon": 0 },
-{ "label": "38/4", "node": 3588, "naklon": 0 },
-{ "label": "38/5", "node": 3493, "naklon": 0 },
-{ "label": "38/6", "node": 3580, "naklon": 0 },
-{ "label": "38/7", "node": 3572, "naklon": 0 },
-{ "label": "38/8", "node": 3506, "naklon": 0 },
-{ "label": "38/9", "node": 3503, "naklon": 0 },
-{ "label": "38/10", "node": 3579, "naklon": 0 },
-{ "label": "38/11", "node": 3586, "naklon": 0 },
-{ "label": "38/12", "node": 3495, "naklon": 5 },
-{ "label": "38/13", "node": 3492, "naklon": 5 },
-{ "label": "38/14", "node": 3532, "naklon": 5 },
-{ "label": "38/15", "node": 3574, "naklon": 5 },
-{ "label": "38/16", "node": 4140, "naklon": 5 },
-{ "label": "38/17", "node": 3795, "naklon": 5 },
-{ "label": "38/18", "node": 3788, "naklon": 5 },
-{ "label": "38/19", "node": 3796, "naklon": 5 },
-{ "label": "38/20", "node": 3797, "naklon": 5 },
-{ "label": "38/21", "node": 3798, "naklon": 5 },
-{ "label": "38/22", "node": 3786, "naklon": 5 },
-{ "label": "38/23", "node": 4067, "naklon": 5 },
-{ "label": "38/24", "node": 3773, "naklon": 5 },
-{ "label": "38/25", "node": 3774, "naklon": 5 },
-{ "label": "38/26", "node": 3789, "naklon": 5 },
-{ "label": "38/27", "node": 3520, "naklon": null },
-{ "label": "38/29", "node": 3577, "naklon": 5 },
-{ "label": "38/31", "node": 3530, "naklon": null },
-{ "label": "38/33", "node": 3488, "naklon": 5 },
-{ "label": "38/34", "node": 3505, "naklon": 5 },
-{ "label": "38/36", "node": 3497, "naklon": 5 },
-{ "label": "38/37", "node": 3490, "naklon": 5 },
-{ "label": "38/39", "node": 3585, "naklon": 5 },
-{ "label": "38/40", "node": 3582, "naklon": 5 },
-{ "label": "38/41", "node": 3507, "naklon": 5 },
-{ "label": "38/42", "node": 3484, "naklon": 5 },
-{ "label": "38/43", "node": 3501, "naklon": 5 },
-{ "label": "38/44", "node": 3581, "naklon": 5 },
-{ "label": "38/45", "node": 4192, "naklon": 5 },
-{ "label": "38/46", "node": 3576, "naklon": 5 },
-{ "label": "38/47", "node": 3489, "naklon": 5 },
-{ "label": "38/48", "node": 3573, "naklon": 5 },
-{ "label": "38/49", "node": 3504, "naklon": 5 },
-{ "label": "38/50", "node": 3794, "naklon": 5 },
-{ "label": "38/51", "node": 3485, "naklon": 5 },
-{ "label": "38/52", "node": 3482, "naklon": 5 },
-{ "label": "38/53", "node": 3575, "naklon": 5 },
-{ "label": "38/54", "node": 3499, "naklon": 5 },
-{ "label": "38/55", "node": 3494, "naklon": 5 },
-{ "label": "38/56", "node": 3583, "naklon": 5 },
-{ "label": "38/57", "node": 3570, "naklon": 5 },
-{ "label": "38/58", "node": 3500, "naklon": 0 },
-{ "label": "38/63", "node": 3510, "naklon": null },
-{ "label": "38/64", "node": 3512, "naklon": null },
-{ "label": "38/67", "node": 3535, "naklon": null },
-{ "label": "38/68", "node": 3531, "naklon": null },
-{ "label": "38/69", "node": 3537, "naklon": null },
-{ "label": "39/1", "node": 3522, "naklon": 10 },
-{ "label": "39/2", "node": 4018, "naklon": 10 },
-{ "label": "39/3", "node": 4019, "naklon": 10 },
-{ "label": "39/4", "node": 4154, "naklon": 5 },
-{ "label": "39/5", "node": 3907, "naklon": 5 },
-{ "label": "39/6", "node": 4148, "naklon": 0 },
-{ "label": "39/7", "node": 4153, "naklon": 0 },
-{ "label": "39/8", "node": 3938, "naklon": 0 },
-{ "label": "39/9", "node": 3802, "naklon": 0 },
-{ "label": "39/10", "node": 4015, "naklon": 0 },
-{ "label": "39/11", "node": 3929, "naklon": 0 },
-{ "label": "39/12", "node": 3946, "naklon": 0 },
-{ "label": "39/13", "node": 4014, "naklon": 0 },
-{ "label": "39/14", "node": 4155, "naklon": 0 },
-{ "label": "39/15", "node": 4149, "naklon": 0 },
-{ "label": "39/16", "node": 3642, "naklon": 0 },
-{ "label": "39/17", "node": 3636, "naklon": 5 },
-{ "label": "39/18", "node": 3991, "naklon": 0 },
-{ "label": "39/19", "node": 3994, "naklon": 0 },
-{ "label": "39/20", "node": 3990, "naklon": 0 },
-{ "label": "39/21", "node": 3967, "naklon": 0 },
-{ "label": "39/22", "node": 3977, "naklon": 0 },
-{ "label": "39/23", "node": 3757, "naklon": 15 },
-{ "label": "39/24", "node": 3633, "naklon": 15 },
-{ "label": "39/25", "node": 3744, "naklon": 15 },
-{ "label": "39/26", "node": 4023, "naklon": 5 },
-{ "label": "39/27", "node": 3720, "naklon": 5 },
-{ "label": "39/28", "node": 3734, "naklon": 5 },
-{ "label": "39/29", "node": 3741, "naklon": 5 },
-{ "label": "39/30", "node": 3721, "naklon": 5 },
-{ "label": "39/31", "node": 3845, "naklon": 0 },
-{ "label": "39/32", "node": 3840, "naklon": 0 },
-{ "label": "39/33", "node": 3837, "naklon": null },
-{ "label": "39/34", "node": 3839, "naklon": 0 },
-{ "label": "41/1", "node": 3542, "naklon": null },
-{ "label": "41/2", "node": 3566, "naklon": null },
-{ "label": "41/3", "node": 3548, "naklon": null },
-{ "label": "41/4", "node": 3515, "naklon": null },
-{ "label": "41/5", "node": 3559, "naklon": null },
-{ "label": "41/6", "node": 3509, "naklon": null },
-{ "label": "41/7", "node": 3524, "naklon": null },
-{ "label": "41/8", "node": 3518, "naklon": null },
-{ "label": "41/9", "node": 3182, "naklon": null },
-{ "label": "41/10", "node": 3187, "naklon": null },
-{ "label": "41/11", "node": 3195, "naklon": 0 },
-{ "label": "41/12", "node": 3857, "naklon": 0 },
-{ "label": "41/13", "node": 3183, "naklon": 0 },
-{ "label": "41/14", "node": 3177, "naklon": 0 },
-{ "label": "41/15", "node": 3189, "naklon": 0 },
-{ "label": "41/16", "node": 3186, "naklon": 0 },
-{ "label": "42/1", "node": 3178, "naklon": 0 },
-{ "label": "42/2", "node": 3219, "naklon": 0 },
-{ "label": "42/3", "node": 3475, "naklon": 0 },
-{ "label": "42/4", "node": 3175, "naklon": 0 },
-{ "label": "42/5", "node": 3222, "naklon": 0 },
-{ "label": "42/6", "node": 3221, "naklon": 0 },
-{ "label": "42/7", "node": 3181, "naklon": 0 },
-{ "label": "42/8", "node": 3180, "naklon": 0 },
-{ "label": "42/9", "node": 3218, "naklon": 0 },
-{ "label": "42/10", "node": 3176, "naklon": 0 },
-{ "label": "42/11", "node": 3174, "naklon": 0 },
-{ "label": "42/12", "node": 3220, "naklon": 0 },
-{ "label": "42/13", "node": 3533, "naklon": null },
-{ "label": "42/14", "node": 3543, "naklon": null },
-{ "label": "42/15", "node": 3554, "naklon": null },
-{ "label": "42/16", "node": 3549, "naklon": null },
-{ "label": "43/1", "node": 2857, "naklon": 5 },
-{ "label": "43/2", "node": 2752, "naklon": 5 },
-{ "label": "43/3", "node": 2753, "naklon": 5 },
-{ "label": "43/4", "node": 3024, "naklon": 5 },
-{ "label": "43/5", "node": 2754, "naklon": 5 },
-{ "label": "43/6", "node": 4423, "naklon": 5 },
-{ "label": "43/7", "node": 4368, "naklon": 5 },
-{ "label": "43/8", "node": 2978, "naklon": 5 },
-{ "label": "43/9", "node": 2868, "naklon": 5 },
-{ "label": "43/10", "node": 4377, "naklon": 5 },
-{ "label": "43/11", "node": 2757, "naklon": 5 },
-{ "label": "43/12", "node": 2970, "naklon": 5 },
-{ "label": "43/13", "node": 2758, "naklon": 5 },
-{ "label": "43/14", "node": 4378, "naklon": 5 },
-{ "label": "43/15", "node": 2759, "naklon": 5 },
-{ "label": "43/16", "node": 4342, "naklon": 5 },
-{ "label": "43/17", "node": 3026, "naklon": null },
-{ "label": "43/18", "node": 2986, "naklon": null },
-{ "label": "43/19", "node": 4343, "naklon": null },
-{ "label": "43/20", "node": 2760, "naklon": null },
-{ "label": "43/21", "node": 4379, "naklon": null },
-{ "label": "43/22", "node": 2971, "naklon": null },
-{ "label": "43/23", "node": 2761, "naklon": null },
-{ "label": "43/24", "node": 2762, "naklon": null },
-{ "label": "43/25", "node": 4339, "naklon": null },
-{ "label": "43/26", "node": 4380, "naklon": null },
-{ "label": "43/27", "node": 2975, "naklon": null },
-{ "label": "43/28", "node": 3003, "naklon": null },
-{ "label": "43/29", "node": 4338, "naklon": null },
-{ "label": "43/30", "node": 3002, "naklon": null },
-{ "label": "43/31", "node": 4345, "naklon": null },
-{ "label": "43/32", "node": 2979, "naklon": null },
-{ "label": "43/33", "node": 2989, "naklon": null },
-{ "label": "43/34", "node": 2996, "naklon": null },
-{ "label": "43/35", "node": 2972, "naklon": null },
-{ "label": "43/36", "node": 2988, "naklon": null },
-{ "label": "43/37", "node": 4344, "naklon": null },
-{ "label": "43/38", "node": 3022, "naklon": null },
-{ "label": "43/39", "node": 4341, "naklon": null },
-{ "label": "43/40", "node": 2983, "naklon": null },
-{ "label": "43/41", "node": 2995, "naklon": null },
-{ "label": "43/42", "node": 2763, "naklon": null },
-{ "label": "43/43", "node": 2764, "naklon": null },
-{ "label": "43/44", "node": 2765, "naklon": null },
-{ "label": "43/45", "node": 2766, "naklon": null },
-{ "label": "43/46", "node": 2767, "naklon": null },
-{ "label": "43/47", "node": 2768, "naklon": null },
-{ "label": "43/48", "node": 3018, "naklon": null },
-{ "label": "43/49", "node": 2982, "naklon": null },
-{ "label": "43/50", "node": 3019, "naklon": 0 },
-{ "label": "43/51", "node": 3013, "naklon": null },
-{ "label": "43/52", "node": 3007, "naklon": null },
-{ "label": "43/53", "node": 2980, "naklon": null },
-{ "label": "43/54", "node": 3011, "naklon": null },
-{ "label": "43/55", "node": 2672, "naklon": null },
-{ "label": "43/56", "node": 2673, "naklon": null },
-{ "label": "43/57", "node": 2674, "naklon": null },
-{ "label": "43/58", "node": 2675, "naklon": null },
-{ "label": "43/59", "node": 2676, "naklon": null },
-{ "label": "43/60", "node": 2677, "naklon": null },
-{ "label": "43/61", "node": 2678, "naklon": null },
-{ "label": "43/62", "node": 2679, "naklon": null },
-{ "label": "43/63", "node": 2680, "naklon": null },
-{ "label": "43/64", "node": 2840, "naklon": null },
-{ "label": "43/65", "node": 2682, "naklon": null },
-{ "label": "43/66", "node": 2683, "naklon": null },
-{ "label": "43/67", "node": 2684, "naklon": 0 },
-{ "label": "43/68", "node": 2685, "naklon": null },
-{ "label": "43/69", "node": 2686, "naklon": null },
-{ "label": "43/70", "node": 2687, "naklon": null },
-{ "label": "43/71", "node": 2688, "naklon": null },
-{ "label": "43/72", "node": 2689, "naklon": null },
-{ "label": "43/73", "node": 2690, "naklon": null },
-{ "label": "43/74", "node": 2691, "naklon": null },
-{ "label": "43/75", "node": 2692, "naklon": null },
-{ "label": "43/76", "node": 2693, "naklon": 0 },
-{ "label": "43/77", "node": 2694, "naklon": null },
-{ "label": "43/78", "node": 2695, "naklon": null },
-{ "label": "43/79", "node": 2696, "naklon": 0 },
-{ "label": "43/80", "node": 2697, "naklon": null },
-{ "label": "43/81", "node": 2698, "naklon": 0 },
-{ "label": "43/82", "node": 2699, "naklon": null },
-{ "label": "43/83", "node": 2700, "naklon": 0 },
-{ "label": "43/84", "node": 2744, "naklon": null },
-{ "label": "43/85", "node": 2745, "naklon": 0 },
-{ "label": "43/86", "node": 2746, "naklon": null },
-{ "label": "43/87", "node": 2747, "naklon": 0 },
-{ "label": "43/88", "node": 2748, "naklon": null },
-{ "label": "43/89", "node": 2749, "naklon": 0 },
-{ "label": "43/90", "node": 2841, "naklon": null },
-{ "label": "45/1", "node": 4237, "naklon": 5 },
-{ "label": "45/2", "node": 4226, "naklon": 5 },
-{ "label": "45/3", "node": 4242, "naklon": 5 },
-{ "label": "45/4", "node": 4179, "naklon": 5 },
-{ "label": "45/5", "node": 4247, "naklon": 5 },
-{ "label": "45/6", "node": 4245, "naklon": 5 },
-{ "label": "45/7", "node": 3872, "naklon": 5 },
-{ "label": "45/8", "node": 4175, "naklon": 5 },
-{ "label": "45/9", "node": 4236, "naklon": 5 },
-{ "label": "45/10", "node": 4170, "naklon": 5 },
-{ "label": "45/11", "node": 4238, "naklon": 5 },
-{ "label": "45/12", "node": 4246, "naklon": 5 },
-{ "label": "45/13", "node": 4166, "naklon": 5 },
-{ "label": "45/14", "node": 4227, "naklon": 5 },
-{ "label": "45/15", "node": 4171, "naklon": 5 },
-{ "label": "45/16", "node": 4180, "naklon": 5 },
-{ "label": "45/17", "node": 4244, "naklon": 5 },
-{ "label": "45/18", "node": 4199, "naklon": 5 },
-{ "label": "45/19", "node": 4239, "naklon": 5 },
-{ "label": "45/20", "node": 4207, "naklon": 5 },
-{ "label": "45/21", "node": 4223, "naklon": 5 },
-{ "label": "45/22", "node": 4230, "naklon": 5 },
-{ "label": "45/23", "node": 4233, "naklon": 5 },
-{ "label": "45/24", "node": 4222, "naklon": 5 },
-{ "label": "45/25", "node": 4217, "naklon": 5 },
-{ "label": "45/26", "node": 4243, "naklon": 5 },
-{ "label": "45/27", "node": 4200, "naklon": 5 },
-{ "label": "45/28", "node": 4228, "naklon": 5 },
-{ "label": "45/29", "node": 4211, "naklon": 5 },
-{ "label": "45/30", "node": 4234, "naklon": 5 },
-{ "label": "45/31", "node": 4235, "naklon": 5 },
-{ "label": "45/32", "node": 4203, "naklon": 5 },
-{ "label": "45/33", "node": 4240, "naklon": 5 },
-{ "label": "45/34", "node": 4224, "naklon": 5 },
-{ "label": "45/35", "node": 4232, "naklon": 5 },
-{ "label": "45/36", "node": 4231, "naklon": 5 },
-{ "label": "45/37", "node": 4161, "naklon": 5 },
-{ "label": "45/38", "node": 4225, "naklon": 5 },
-{ "label": "45/39", "node": 4241, "naklon": 5 },
-{ "label": "45/40", "node": 4229, "naklon": 5 },
-{ "label": "45/41", "node": 4221, "naklon": 5 },
-{ "label": "45/42", "node": 4212, "naklon": 5 },
-{ "label": "45/43", "node": 4216, "naklon": 5 },
-{ "label": "45/44", "node": 3864, "naklon": null },
-{ "label": "46/1", "node": 3806, "naklon": 5 },
-{ "label": "46/2", "node": 3813, "naklon": 5 },
-{ "label": "46/3", "node": 3815, "naklon": 5 },
-{ "label": "46/4", "node": 3807, "naklon": 5 },
-{ "label": "46/5", "node": 3895, "naklon": 5 },
-{ "label": "46/6", "node": 3809, "naklon": 5 },
-{ "label": "46/7", "node": 3820, "naklon": 5 },
-{ "label": "46/8", "node": 3805, "naklon": 5 },
-{ "label": "46/9", "node": 3894, "naklon": 0 },
-{ "label": "46/10", "node": 4055, "naklon": 0 },
-{ "label": "46/11", "node": 3812, "naklon": 5 },
-{ "label": "46/12", "node": 3822, "naklon": 5 },
-{ "label": "46/13", "node": 3821, "naklon": 5 },
-{ "label": "46/14", "node": 3808, "naklon": 5 },
-{ "label": "46/15", "node": 3799, "naklon": 5 },
-{ "label": "46/16", "node": 3816, "naklon": 5 },
-{ "label": "46/17", "node": 3751, "naklon": 5 },
-{ "label": "46/18", "node": 3814, "naklon": 5 },
-{ "label": "46/19", "node": 4044, "naklon": 0 },
-{ "label": "46/20", "node": 3931, "naklon": 0 },
-{ "label": "46/21", "node": 3902, "naklon": 5 },
-{ "label": "46/22", "node": 3916, "naklon": 5 },
-{ "label": "46/23", "node": 3892, "naklon": 5 },
-{ "label": "46/24", "node": 3914, "naklon": 5 },
-{ "label": "46/25", "node": 3898, "naklon": 5 },
-{ "label": "46/26", "node": 3897, "naklon": 5 },
-{ "label": "46/27", "node": 3885, "naklon": 5 },
-{ "label": "46/28", "node": 3906, "naklon": 5 },
-{ "label": "46/29", "node": 3930, "naklon": 0 },
-{ "label": "46/30", "node": 3936, "naklon": 0 },
-{ "label": "46/31", "node": 3860, "naklon": 5 },
-{ "label": "46/32", "node": 3841, "naklon": 5 },
-{ "label": "46/33", "node": 3873, "naklon": 5 },
-{ "label": "46/34", "node": 3854, "naklon": 5 },
-{ "label": "46/35", "node": 3939, "naklon": 5 },
-{ "label": "46/36", "node": 3858, "naklon": 5 },
-{ "label": "46/37", "node": 3940, "naklon": 5 },
-{ "label": "46/38", "node": 4035, "naklon": 5 },
-{ "label": "47/1", "node": 3373, "naklon": 0 },
-{ "label": "47/2", "node": 3374, "naklon": 0 },
-{ "label": "47/3", "node": 3384, "naklon": 0 },
-{ "label": "47/4", "node": 3385, "naklon": 0 },
-{ "label": "48/1", "node": 4051, "naklon": 5 },
-{ "label": "48/2", "node": 4041, "naklon": 5 },
-{ "label": "48/3", "node": 4056, "naklon": 5 },
-{ "label": "48/4", "node": 3875, "naklon": 5 },
-{ "label": "48/5", "node": 4061, "naklon": 5 },
-{ "label": "48/6", "node": 4047, "naklon": 5 },
-{ "label": "48/7", "node": 4060, "naklon": 5 },
-{ "label": "48/8", "node": 4059, "naklon": 5 },
-{ "label": "48/9", "node": 4058, "naklon": 5 },
-{ "label": "48/10", "node": 3635, "naklon": 5 },
-{ "label": "48/11", "node": 3640, "naklon": 5 },
-{ "label": "48/12", "node": 3747, "naklon": 5 },
-{ "label": "48/13", "node": 3629, "naklon": 5 },
-{ "label": "48/14", "node": 4048, "naklon": 5 },
-{ "label": "48/15", "node": 4063, "naklon": 5 },
-{ "label": "48/16", "node": 4062, "naklon": 5 },
-{ "label": "48/17", "node": 4043, "naklon": 5 },
-{ "label": "48/18", "node": 4052, "naklon": 5 },
-{ "label": "48/19", "node": 4042, "naklon": 5 },
-{ "label": "48/20", "node": 4053, "naklon": 5 },
-{ "label": "50/15A", "node": 4167, "naklon": null },
-{ "label": "50/15B", "node": 4159, "naklon": null },
-{ "label": "50/1", "node": 4183, "naklon": 0 },
-{ "label": "50/2", "node": 4157, "naklon": 0 },
-{ "label": "50/3", "node": 4160, "naklon": 0 },
-{ "label": "50/4", "node": 4173, "naklon": 0 },
-{ "label": "50/5", "node": 4177, "naklon": 0 },
-{ "label": "50/6", "node": 4174, "naklon": 0 },
-{ "label": "50/7", "node": 4178, "naklon": 0 },
-{ "label": "50/8", "node": 4195, "naklon": 0 },
-{ "label": "50/9", "node": 4169, "naklon": 0 },
-{ "label": "50/10", "node": 4162, "naklon": 0 },
-{ "label": "50/11", "node": 4158, "naklon": 0 },
-{ "label": "50/12", "node": 4182, "naklon": 0 },
-{ "label": "50/13", "node": 4194, "naklon": 0 },
-{ "label": "50/14", "node": 4184, "naklon": 0 },
-{ "label": "50/16", "node": 4197, "naklon": null },
-{ "label": "50/17", "node": 4164, "naklon": null },
-{ "label": "50/18", "node": 3306, "naklon": null },
-{ "label": "50/19", "node": 4168, "naklon": null },
-{ "label": "50/20", "node": 4193, "naklon": null },
-{ "label": "50/21", "node": 4187, "naklon": null },
-{ "label": "50/22", "node": 4163, "naklon": null },
-{ "label": "50/23", "node": 4165, "naklon": null },
-{ "label": "50/24", "node": 4185, "naklon": null },
-{ "label": "50/25", "node": 3904, "naklon": null },
-{ "label": "53/1", "node": 2619, "naklon": 0 },
-{ "label": "53/2", "node": 2623, "naklon": 0 },
-{ "label": "53/3", "node": 2617, "naklon": 0 },
-{ "label": "53/4", "node": 2622, "naklon": 0 },
-{ "label": "53/5", "node": 2618, "naklon": 0 },
-{ "label": "53/6", "node": 2626, "naklon": 0 },
-{ "label": "53/7", "node": 2869, "naklon": 0 },
-{ "label": "53/8", "node": 2613, "naklon": 0 },
-{ "label": "53/9", "node": 2608, "naklon": 0 },
-{ "label": "53/10", "node": 2611, "naklon": 0 },
-{ "label": "53/11", "node": 2598, "naklon": 0 },
-{ "label": "53/12", "node": 3528, "naklon": 0 },
-{ "label": "53/13", "node": 3545, "naklon": 0 },
-{ "label": "53/14", "node": 2620, "naklon": 0 },
-{ "label": "53/15", "node": 2612, "naklon": 0 },
-{ "label": "53/16", "node": 2615, "naklon": 0 },
-{ "label": "53/17", "node": 3722, "naklon": 0 },
-{ "label": "53/18", "node": 2624, "naklon": 0 },
-{ "label": "53/19", "node": 2609, "naklon": 0 },
-{ "label": "53/20", "node": 2625, "naklon": 0 },
-{ "label": "53/21", "node": 2602, "naklon": 0 },
-{ "label": "53/22", "node": 2610, "naklon": 0 },
-{ "label": "53/23", "node": 2599, "naklon": 0 },
-{ "label": "53/24", "node": 2605, "naklon": 0 },
-{ "label": "53/25", "node": 2593, "naklon": 0 },
-{ "label": "53/26", "node": 3074, "naklon": 0 },
-{ "label": "53/27", "node": 2740, "naklon": 0 },
-{ "label": "53/28", "node": 2614, "naklon": 0 },
-{ "label": "53/29", "node": 2601, "naklon": 0 },
-{ "label": "53/30", "node": 4196, "naklon": 0 },
-{ "label": "53/31", "node": 2607, "naklon": 0 },
-{ "label": "53/32", "node": 2582, "naklon": 0 },
-{ "label": "53/33", "node": 2594, "naklon": 0 },
-{ "label": "53/34", "node": 2589, "naklon": 0 },
-{ "label": "53/35", "node": 2596, "naklon": 0 },
-{ "label": "53/36", "node": 2603, "naklon": 0 },
-{ "label": "53/37", "node": 2597, "naklon": 0 },
-{ "label": "53/38", "node": 2590, "naklon": 0 },
-{ "label": "53/39", "node": 2581, "naklon": 0 },
-{ "label": "53/40", "node": 2583, "naklon": 0 },
-{ "label": "53/41", "node": 2580, "naklon": 0 },
-{ "label": "53/42", "node": 2579, "naklon": 0 },
-{ "label": "53/43", "node": 2797, "naklon": 0 },
-{ "label": "53/44", "node": 2577, "naklon": 0 },
-{ "label": "53/45", "node": 2586, "naklon": 0 },
-{ "label": "53/46", "node": 2588, "naklon": 0 },
-{ "label": "53/47", "node": 2591, "naklon": 0 },
-{ "label": "53/48", "node": 2592, "naklon": 0 },
-{ "label": "53/49", "node": 2573, "naklon": 0 },
-{ "label": "53/50", "node": 2595, "naklon": 0 },
-{ "label": "53/51", "node": 2587, "naklon": 0 },
-{ "label": "53/52", "node": 2578, "naklon": 0 },
-{ "label": "53/53", "node": 2574, "naklon": 0 },
-{ "label": "53/54", "node": 2571, "naklon": 0 },
-{ "label": "53/55", "node": 2570, "naklon": 0 },
-{ "label": "53/56", "node": 2576, "naklon": 0 },
-{ "label": "53/57", "node": 2881, "naklon": 0 },
-{ "label": "53/58", "node": 2575, "naklon": 0 },
-{ "label": "53/59", "node": 2572, "naklon": 0 },
-{ "label": "53/60", "node": 2569, "naklon": 0 },
-{ "label": "55/1", "node": 4324, "naklon": 0 },
-{ "label": "55/2", "node": 4319, "naklon": 0 },
-{ "label": "55/3", "node": 4327, "naklon": 0 },
-{ "label": "55/4", "node": 4333, "naklon": 0 },
-{ "label": "55/5", "node": 4332, "naklon": 0 },
-{ "label": "55/6", "node": 4320, "naklon": 0 },
-{ "label": "55/7", "node": 4317, "naklon": 0 },
-{ "label": "55/8", "node": 4318, "naklon": 0 },
-{ "label": "55/9", "node": 4328, "naklon": 0 },
-{ "label": "55/10", "node": 4323, "naklon": 0 },
-{ "label": "55/11", "node": 4325, "naklon": 0 },
-{ "label": "55/12", "node": 4326, "naklon": 0 },
-{ "label": "55/13", "node": 4316, "naklon": 0 },
-{ "label": "55/14", "node": 4322, "naklon": 0 },
-{ "label": "55/15", "node": 4331, "naklon": 0 },
-{ "label": "55/16", "node": 4321, "naklon": 0 },
-{ "label": "55/17", "node": 4315, "naklon": 0 },
-{ "label": "55/18", "node": 4329, "naklon": 0 },
-{ "label": "55/19", "node": 4334, "naklon": 0 },
-{ "label": "55/20", "node": 4330, "naklon": 0 }
-];
-
-module.exports = { naklony };
diff --git a/databases/nodes.table b/databases/nodes.table
index b2f13d9..57331db 100644
--- a/databases/nodes.table
+++ b/databases/nodes.table
@@ -1,2 +1,31 @@
-node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean|time_of_last_communication:number
-+|638|rDbQ84xzwgdqEoPm3kbJQWk9anOZY1RXyBv2LVM6|3|{"intervals":[{"cct":3000,"value":20,"end_time":"20:00","start_time":"13:00"},{"cct":3000,"value":10,"end_time":"05:30","start_time":"20:00"},{"cct":3000,"value":20,"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":-20,"dusk_astro_clock_offset":20,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}|1|0|1725885127396|............................................................................................................................................................................................................................................................
+node:number|tbname:string|line:number|profile:string|processed:boolean|status:boolean
++|3522|RO8rjaBDy21qPQJzW7oD96ApK3xmNleVZg9Ed4Gw|1||1|1|...........
++|4018|3JjOWdylwgNLzxVab7NEznkZ2vG64rq8PEB5QmDo|1||1|1|...........
++|4019|Z5KyJe9nEg1QNbWlX0wWRB0oDjBLdqzR83VGv624|1||1|1|...........
++|4154|1JMYvnx2RzKEo4aWQ7DmN5AL8yZV3m9NBePXbrdj|1||1|0|...........
++|3907|PjLblDgRBO6WQqnxmkJ59r0Jv3ewZN4p5a89yKdY|1||1|1|...........
++|4148|dz4ojlpP85JMgDLZWkQOoGAaKYqQexEr62GXRV1y|1||1|1|...........
++|4153|d5xjWYMwEJon6rLlK7yBYmAqgV4DaOeNB9ZX3Gzb|1||1|1|...........
++|3938|gRoJEyXVx4qD9er287LP1v7wBzGldaPjLWQKm3Mv|1||1|1|...........
++|3802|K94XLav1glVRnyQ6r01BNzkme3YJwBxM5oOzdP2j|1||1|1|...........
++|4015|d9x2V5LGYBzXp4mMRAOBDj7PloaqJwnQj6DgrNe3|1||1|0|...........
++|3929|B5EoxeMVp4zwr8nqW0GjDpARjvD1PNamOGbLg63Z|1||1|1|...........
++|3946|aw4eELG2DlPMdn1JW0B1DnAqQXOZRN3xB5yp8VKr|1||1|1|...........
++|4014|ZmRwd93QL4gaezxEbAxW5971prn2XjlPvGyqJ6BO|1||1|1|...........
++|4155|eod9aRWLVl34Gx1Dn7VoaaA2rz6qjgmpEXwQJN5Z|1||1|1|...........
++|4149|3a5oqJN1bgnx4Ol9dk86NBAByE6jQ8mKDWMpGrLV|1||1|1|...........
++|3642|EjgWGnXaLy9opPOz20n694086BlYM3w1deVQvbKr|1||1|1|...........
++|3636|wvKJdZML6mXP4DzWBAXWNW7jxNloa5g23Ve9Y1ry|1||1|1|...........
++|3991|Nzp2OoJlqn6r1ZgvdA3GWdAabBwP5G4eE3RQmyxD|1||1|1|...........
++|3994|PLBJzmK1r3Gynd6OW0gGdM0e5wV4vx9bDEqNgYR8|1||1|1|...........
++|3990|52dD6ZlV1QaOpRBmbAqKZgkKnGzWMLj4eJq38Pgo|1||1|1|...........
++|3967|rDbQ84xzwgdqEoPm3kbJw3k9anOZY1RXyBv2LVM6|1||1|1|...........
++|3977|E6Kg9oDnLWyzPRMva7vrwa7Jxp4VG58qO2w1lZYe|1||1|1|...........
++|3757|roKgWqY95V3mXMRzyAjm8D7bLjexpJPvaGDBw826|1||1|1|...........
++|3633|nJL5lPMwBx23YpqRe0rlKV7damXvWVbOrD4gNzy8|1||1|1|...........
++|3744|ZmRwd93QL4gaezxEbAxW5O71prn2XjlPvGyqJ6BO|1||1|1|...........
++|4023|eod9aRWLVl34Gx1Dn7VoaMA2rz6qjgmpEXwQJN5Z|1||1|1|...........
++|3720|3a5oqJN1bgnx4Ol9dk86NZAByE6jQ8mKDWMpGrLV|1||1|1|...........
++|3734|EjgWGnXaLy9opPOz20n69V086BlYM3w1deVQvbKr|1||1|1|...........
++|3741|wvKJdZML6mXP4DzWBAXWN17jxNloa5g23Ve9Y1ry|1||1|1|...........
++|3721|Nzp2OoJlqn6r1ZgvdA3GWKAabBwP5G4eE3RQmyxD|1||0|0|...........
diff --git a/databases/nodes_original/nodes_original.table b/databases/nodes_original/nodes_original.table
deleted file mode 100644
index d8670f9..0000000
--- a/databases/nodes_original/nodes_original.table
+++ /dev/null
@@ -1 +0,0 @@
-[{"3815": "B5EoxeMVp4zwr8nqW0GjjoARjvD1PNamOGbLg63Z"}, {"3799": "roKgWqY95V3mXMRzyAjmmj7bLjexpJPvaGDBw826"}]
diff --git a/databases/notifications.table b/databases/notifications.table
index f7c96cb..a0590d3 100644
--- a/databases/notifications.table
+++ b/databases/notifications.table
@@ -1,5 +1,5 @@
key:string|weight:string|sk:string|en:string
-+|switching_profile_point_applied_to_line|INFORMATIONAL|Aplikovaný bod spínacieho profilu na línií č. ${line} : ${value}|Switching profile point applied to line no. ${line} : ${value}|...............
++|switching_profile_point_applied_to_line|INFORMATIONAL|Aplikovaný bod spínacieho profilu na línií č. ${line} : ${value}|Switching profile point applied to line no. ${line} : ${value}|...............
+|dusk_has_occured|INFORMATIONAL|Nastal súmrak: ${value}|Dusk has occured: ${value}|...............
+|dawn_has_occured|INFORMATIONAL|Nastal úsvit: ${value}|Dawn has occured: ${value}|...............
+|dimming_profile_was_successfully_received_by_node|NOTICE|Stmievací profil bol úspešne prijatý nodom č. ${node}|Dimming profile was successfully received by node no. ${node}|...............
@@ -20,12 +20,9 @@ key:string|weight:string|sk:string|en:string
+|power_supply_works_correctly|NOTICE|Napájací zdroj pracuje správne|Power supply works correctly|...............
+|battery_level_is_low|ERROR|Batéria má nízku úroveň napätia|Battery level is low|...............
+|battery_level_is_ok|NOTICE|Batéria má správnu úroveň napätia|Battery level is OK|...............
-+|door_main_open|NOTICE|Hlavné dvere boli otvorené|Main door has been opened|...............
-+|door_em_open|NOTICE|Dvere silovej časti boli otvorené|Power door has been opened|...............
-+|door_main_open_without_permission|WARNING|Hlavné dvere boli otvorené bez povolenia - zapnutá siréna|Main door has been opened without permission - alarm is on|...............
-+|door_em_open_without_permission|WARNING|Dvere silovej časti boli otvorené bez povolenia|Power door has been opened without permission|...............
-+|door_main_close|NOTICE|Hlavné dvere boli zatvorené|Main door has been closed|...............
-+|door_em_close|NOTICE|Dvere silovej časti boli zatvorené|Power door has been closed|...............
++|door_has_been_open|NOTICE|Dvere boli otvorené|Door has been open|...............
++|door_has_been_closed|NOTICE|Dvere boli zatvorené|Door has been closed|...............
++|door_has_been_open_without_permision_alarm_is_on|WARNING|Dvere boli otvorené bez povolania - zapnutá siréna|Door has been open without permision - alarm is on|...............
+|state_of_contactor_for_line|INFORMATIONAL|Stav stýkača pre líniu č. ${line} je ${value}|State of contactor for line no. ${line} is ${value}|...............
+|local_database_is_corrupted|CRITICAL|||...............
+|electrometer_nok|ERROR|Elektromer neodpovedá|Electrometer is not responding|...............
@@ -37,5 +34,4 @@ key:string|weight:string|sk:string|en:string
+|twilight_sensor_ok|NOTICE|Sensor súmraku znovu odpovedá|Twilight sensor is responding again|...............
+|lamps_have_turned_on|NOTICE|Lampy sa zapli|Lamps have turned on|...............
+|lamps_have_turned_off|NOTICE|Lampy sa vypli|Lamps have turned off|...............
-+|flow_restart|NOTICE|FLOW bol reštartovaný|FLOW has been restarted|...............
-+|nodes_db_changed|NOTICE|Zmena v node databáze|Node db has changed|...............
++|flow_restart|NOTICE|Restart flowu|Flow has been restarted|...............
diff --git a/databases/relays.table b/databases/relays.table
index 40843b1..68e4f06 100644
--- a/databases/relays.table
+++ b/databases/relays.table
@@ -1,5 +1,5 @@
line:number|tbname:string|contactor:number|profile:string
+|0|6lQGaY9RDywdVzObj0PadOkPg4NBn3exEK51LWZq|1||...........
-+|1|JzwxZXOvDj1bVrN4nkWw9Qk8qdyBl3MRKLpGPgaQ|9|{"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|9|{"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|9|{"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}|...........
++|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 5abd2b1..a182df5 100644
--- a/databases/settings.table
+++ b/databases/settings.table
@@ -1,2 +1,2 @@
-rvo_name:string|lang:string|temperature_address:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|project_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number|node_status_nok_time:number|phases:number|cloud_topic:string|has_main_switch:boolean
-+|rvo_senica_22_ip10.0.0.109|en|28.F46E9D0E0000|48.70826502|17.28455203|192.168.252.1|rvo_senica_22_ip10.0.0.109|9excvr7yBcF3gl3kYZGY|1883|0|48|unipi|ttyUSB0|1|20|5|6|3|u109|0|...........................................
+rvo_name:string|lang:string|temperature_adress:string|latitude:number|longitude:number|mqtt_host:string|mqtt_clientid:string|mqtt_username:string|mqtt_port:number|maintanace_mode:boolean|projects_id:number|controller_type:string|serial_port:string|backup_on_failure:boolean|restore_from_backup:number|restore_backup_wait:number
++|rvo_senica_39_10.0.0.132|en|28.427B45920702|48.70826502|17.28455203|192.168.252.1|rvo_senica_39_10.0.0.132|qzSNuCNrLP4OL1v47YEe|1883|0|68|unipi|ttyUSB0|1|20|5|...........................................
diff --git a/databases/tbdatacloud.nosql b/databases/tbdatacloud.nosql
deleted file mode 100644
index e69de29..0000000
diff --git a/databases/total_energy.js b/databases/total_energy.js
deleted file mode 100644
index cc8c018..0000000
--- a/databases/total_energy.js
+++ /dev/null
@@ -1,37 +0,0 @@
-//key is rvo_number, value is max energy when lamps are on
-const total_energy = {
- 1: 580,
- 2: 1100,
- 3: 3700,
- 4: 4100,
- 7: 360,
- 12: 1700,
- 13: 5400,
- 14: 440,
- 15: 6100,
- 16: 4800,
- 20: 1600,
- 21: 1000,
- 22: 2600,
- 23: 1000,
- 25: 2600,
- 33: 240,
- 34: 4000,
- 35: 2700,
- 36: 820,
- 37: 1400,
- 35: 3500,
- 39: 1170,
- 41: 740,
- 42: 660,
- 43: 4900,
- 45: 930,
- 46: 700,
- 47: 1100,
- 48: 1500,
- 50: 3200,
- 55: 1000,
- 56: 5500
-}
-
-module.exports = total_energy;
diff --git a/flow/audit_test_panel.csv b/flow/audit_test_panel.csv
new file mode 100644
index 0000000..907a6a9
--- /dev/null
+++ b/flow/audit_test_panel.csv
@@ -0,0 +1,48 @@
+LumDimm;NODE (HEX);NODE (DEC);Line;TB name
+1;299;665;3;gbv4nzqxW0XGAPKVNk8kr25ZQ2l3O6LRBprM97ew
+2;28A;650;3;0XYElWeKBNJn1gdoMG8lYdDALkPvj4V3xra2q6mO
+3;296;662;3;gbv4nzqxW0XGAPKVNk8kW48ZQ2l3O6LRBprM97ew
+4;297;663;1;LpkVlmq4b3jMwJQxBZ8akayrXAP6o97Ke0aOYEg2
+5;29C;668;3;lekrmdvO0BQG1ZW4AV8jeZ5M39xnN2wEbRgPjXLp
+6;2B1;689;3;q0rElBPdL6kxMAjnzVDRl95emNZY7oOv2wK9gb31
+7;2AB;683;3;XKQbz3WAwY21dGa0R453rWyJm9PZOjqlvpr6Nkeo
+8;2B0;688;3;PaGbQ3wBAZWOmRvK9VDpvz5endLJYopEqlkzNMxX
+9;2B9;697;3;joqRYBVL30k9eQWOlZ5qwpD2KJpNEmA6gPxXzwaM
+10;293;659;3;Ymn9oleRxJ0vw17WzAyGwdyEBk4ObdMXj2VgpNLG
+11;294;660;3;gj7zbKV46oQ1p2e0AJ8XqZDG3YNWaRrlOEXvBxmM
+12;295;661;3;laYK7Pomn2bNZXEpedDxAqyOJkQ3WwV49gqxLrAR
+13;2A0;672;2;0XYElWeKBNJn1gdoMG8lON5ALkPvj4V3xra2q6mO
+14;2B4;692;2;l9YkRpoB2vVa0mKqEO8ZGGDjW43eXnJML6GxzbwQ
+15;2B2;690;2;wGjQobgOK0n2YqBZmVDVR3DR9ep6EXA1ka3vzlP7
+16;27C;636;2;M6ogKQW09bOXewAYvZyvJqyJrV1aRnPGE37p42Nx
+17;27B;635;2;Vq2JaWpw1OdBKmNeoj8w605XE40l3kgL76Azb9QP
+18;2B6;694;2;Jm32GR1qpwQxlZza0N5mE15AP96YbOKLogrXVW4e
+19;2B5;693;2;KjbN4q7JPZmexgdnz2yKdn5YAWwO0Q3BMX6ERLoV
+20;2B3;691;1;lekrmdvO0BQG1ZW4AV8jzq8M39xnN2wEbRgPjXLp
+21;27F;639;3;BOjEzGRZ46bnp9wa2A8z76D0JkmW1QPNdrqevXVL
+22;27E;638;3;9xgzG4Op1BrKZPmoQkDrmj8E73ndJNMjavAwX2Re
+23;27D;637;3;koW06PeGrLlBp2YJQE5Ogw5RmMaXKzj3wOAZg9n7
+24;28F;655;2;RMgnK93rkoAazbqdQ4yBYpDZ1YXGx6pmwBeVEP2O
+25;288;648;2;gaMGN4x1e9JlZz0QPRDd9Rym6dVr3OpvqKnoWBbk
+26;298;664;1;oGVzxNWP9lrjaQ7vKODQ7g51gqp62YZREmdw3XBM
+27;29F;671;3;AvVdgzYJZaPx3oMqeED4Oj8NnmKkw716bRO90jLB
+28;280;640;2;WjBL12pg63eX4N9P7zy0XYyEJKmlbkGwZMx0avQV
+29;28B;651;2;qaAOzENGrvpbe0VoK7D6Ld519PZmdg3nl24JLQMk
+30;27A;634;2;NGWamnYqlP1wbgrZQxDAWm5e2X7OVAK69koR04vL
+31;29E;670;2;dlE1VQjYrNx9gZRmb38g1YyoLBO4qaAk2M6JPnG7
+32;281;641;2;vnmG4kJxaXWNBgMQq0D7Mz5e9oZzOAlr6LdR3w2V
+33;278;632;2;LpkVlmq4b3jMwJQxBZ8aM78rXAP6o97Ke0aOYEg2
+34;29D;669;3;Y9aLW03wOZkABvKXbMyL0lyV1xdNj72r4egqGRzJ
+35;2A8;680;1;KL2jNOVpdARa9XvoeJDPga8bkmPBxqn7Ww3gzGQ1
+36;2BA;698;1;mYnBzbeGaAL62jowRv59M35Xq9QpZ0K7O1dg4xVl
+37;29B;667;1;MzXBoWbEZjO0lrpqnRyoJ4DkmVeaNAGdL9g4QKxP
+38;289;649;1;0p2rwdP7aGoOQLJNgAynJNy6xWXbmMe3nvZqlzkV
+39;290;656;1;BrQx3NGKgVMRaXYAo9y1GE8ZzkWnj1le6bdOLE20
+40;2AA;682;1;vnreBJ6PMqgz20pYEL82XQyG1jkWwdQxZVNAOlmK
+41;285;645;1;jklN4JpQAx362o9XYZDN6wDgrWw1P7GEbdBM0vRV
+42;283;643;1;oZmYXEbw9lVWRv1jLxDe9bDdgAMz4PKQnNJ6eB23
+43;282;642;1;pEonaKBOGbj9034MgJ8W3G8qXvxNWVkAPQz21R6L
+44;287;647;1;BLQal6Pn9oz1KmNgek5Yqd50vd2MAbqG3OV7Rp4j
+45;286;646;1;4agVJ9dPQkmp1R2X3EDJKxyrK6ZlNoM0n7qxBOev
+46;29A;666;1;9PpgLEnvk4WMV6RmOJybMGDaeAXzo2BQNG3K17Zw
+47;28E;654;1;Mmp93b2nvd7OoqgBeEyEZq5kjlAV1Y4ZNXwW0zLG
diff --git a/flow/cloudmqttconnect.js b/flow/cloudmqttconnect.js
deleted file mode 100644
index 1fc0e09..0000000
--- a/flow/cloudmqttconnect.js
+++ /dev/null
@@ -1,348 +0,0 @@
-exports.id = 'cloudmqttconnect';
-exports.title = 'Cloud connect mqtt';
-exports.group = 'MQTT';
-exports.color = '#888600';
-exports.version = '1.0.2';
-exports.icon = 'sign-out';
-exports.input = 2;
-exports.output = 2;
-exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
-
-exports.html = `
-
-
-
Hostname or IP address (if not empty - setting will override db setting)
-
-
-
-
-
`;
-
-const { promisifyBuilder } = require('./helper/db_helper');
-const fs = require('fs');
-const mqtt = require('mqtt');
-const nosql = NOSQL('tbdatacloud');
-
-const SEND_TO = {
- debug: 0,
- rpcCall: 1,
-}
-
-//CONFIG
-let saveTelemetryOnError = true;//backup_on_failure overrides this value
-//------------------------
-
-const noSqlFileSizeLimit = 4194304;//use 5MB - 4194304
-let insertNoSqlCounter = 0;
-let insertBackupNoSqlCounter = 0;
-let processingData = false;
-
-let backup_on_failure = true;//== saveTelemetryOnError - create backup client send failure
-let restore_from_backup = 50; //how many rows process at once?
-let restore_backup_wait = 3;//wait seconds
-let lastRestoreTime = 0;
-
-// if there is an error in client connection, flow logs to monitor.txt. Not to log messages every second, we use sendClientError variable
-let sendClientError = true;
-
-exports.install = function(instance) {
-
- var client;
- var opts;
- var clientReady = false;
-
- let o = null; //options
-
- function main() {
- loadSettings();
- }
-
- //set opts according to db settings
- function loadSettings() {
-
- o = instance.options;
- if (!o.topic) o.topic = FLOW.GLOBALS.settings.cloud_topic;
-
- opts = {
- host: o.host,
- port: o.port,
- clientId: o.clientid,
- username: o.username,
- rejectUnauthorized: false,
- resubscribe: false
- };
-
- console.log("wsmqttpublich -> loadSettings from instance.options", o);
-
- connectToTbServer();
- }
-
- function connectToTbServer() {
- var url = "mqtt://" + opts.host + ":" + opts.port;
- console.log("MQTT URL: ", url);
-
- client = mqtt.connect(url, opts);
-
- client.on('connect', function() {
- client.subscribe(`${o.topic}_backward`, (err) => {
- if (!err) {
- console.log("MQTT subscribed");
- }
- });
- instance.status("Connected", "green");
- clientReady = true;
- sendClientError = true;
- });
-
- client.on('reconnect', function() {
- instance.status("Reconnecting", "yellow");
- clientReady = false;
- });
-
- client.on('message', function(topic, message) {
- // message is type of buffer
- message = message.toString();
- if (message[0] === '{') {
-
-
- try {
- message = JSON.parse(message);
- if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
- client.publish(`${o.topic}_forward`, `{"device": "${message.device}", "id": ${message.data.id}, "data": {"success": true}}`, { qos: 1 });
- instance.send(SEND_TO.rpcCall, { "device": message.device, "id": message.data.id, "RPC response": { "success": true } });
- }
- } catch (e) { instance.debug('MQTT: Error parsing data', message) }
-
- instance.send(SEND_TO.rpcCall, { "topic": o.topic, "content": message });
- }
- });
-
- client.on('close', function() {
- clientReady = false;
-
- instance.status("Disconnected", "red");
- instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
- });
-
- client.on('error', function(err) {
- instance.status("Err: " + err.code, "red");
- instance.send(SEND_TO.debug, { "message": "Client ERROR signal received !", "error": err, "opt": opts });
- if (sendClientError) {
- console.log('MQTT client error', err);
- sendClientError = false;
- }
- clientReady = false;
- });
-
- }
-
-
- instance.on('0', function(data) {
-
- if (clientReady) {
- //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();
- }
-
- let stringifiedJson = JSON.stringify(data.data)
- client.publish(`${o.topic}_forward`, stringifiedJson, { qos: 1 });
- }
- else {
- //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
- instance.send(SEND_TO.debug, { "message": "Client unavailable. Data not sent !", "data": data.data });
-
- if (saveTelemetryOnError) {
- //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.on("1", _ => {
- main();
- })
-
- instance.close = function(done) {
- if (clientReady) {
- client.end();
- }
- };
-
-
- function getDbBackupFileCounter(type) {
- var files = fs.readdirSync(__dirname + "/../databases");
-
- let counter = 0;
- for (var i = 0; i < files.length; i++) {
-
- if (files[i] == "tbdatacloud.nosql") continue;
-
- if (files[i].endsWith(".nosql")) {
-
- let pos = files[i].indexOf(".");
- if (pos > -1) {
-
- let fileCounter = counter;
- let firstDigit = files[i].slice(0, pos);
-
- fileCounter = parseInt(firstDigit);
- if (isNaN(fileCounter)) fileCounter = 0;
- //console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
-
- if (type == "max") {
- if (fileCounter > counter) {
- counter = fileCounter;
- }
- }
- else if (type == "min") {
- if (counter == 0) counter = fileCounter;
-
- if (fileCounter < counter) {
- counter = fileCounter;
- }
- }
- }
- }
-
- }
-
- if (type == "max") counter++;
-
- return counter;
- }
-
- const makeBackupFromDbFile = async () => {
-
- if (!saveTelemetryOnError) return;
-
- //to avoid large file: tbdata.nosql
-
- //init value is 0!
- if (insertNoSqlCounter > 0) {
- --insertNoSqlCounter;
- return;
- }
-
- insertNoSqlCounter = 100;
-
- let source = __dirname + "/../databases/tbdatacloud.nosql";
-
- var stats = fs.statSync(source);
- var fileSizeInBytes = stats.size;
-
- if (fileSizeInBytes > noSqlFileSizeLimit) {
-
- let counter = 1;
- counter = getDbBackupFileCounter("max");
-
- let destination = __dirname + "/../databases/" + counter + "." + "tbdatacloud.nosql";
-
- //make backup file
- fs.copyFileSync(source, destination);
- //fs.renameSync(p, p + "." + counter);
-
- //clear tbdata.nosql
- fs.writeFileSync(source, "");
- fs.truncateSync(source, 0);
-
- }
- }
-
- const processDataFromDatabase = async () => {
-
- if (restore_from_backup <= 0) return;
-
- //calculate diff
- const now = new Date();
- let currentTime = now.getTime();
- let diff = currentTime - lastRestoreTime;
-
- if ((diff / 1000) < restore_backup_wait) {
- //console.log("*********restore_backup_wait", diff, restore_backup_wait);
- return;
- }
-
- processingData = true;
-
- //get filename to process
- let counter = getDbBackupFileCounter("min");
-
- //we have some backup files
- let dataBase = 'tbdata';
-
- var nosql;
- if (counter == 0) dataBase = 'tbdatacloud';
- else dataBase = counter + "." + 'tbdatacloud';
-
- nosql = NOSQL(dataBase);
-
- //select all data - use limit restore_from_backup
- let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
-
- for (let i = 0; i < records.length; i++) {
- if (clientReady) {
-
- let item = records[i];
- let id = item.id;
-
- if (id !== undefined) {
- //console.log("------------processDataFromDatabase - remove", id, dataBase, i);
-
- try {
-
- let message = JSON.parse(JSON.stringify(item));
- delete message.id;
- client.publish(`${o.topic}_forward`, JSON.stringify(message), { qos: 1 });
-
- //remove from database
- await promisifyBuilder(nosql.remove().where("id", id));
-
- } catch (error) {
- //process error
- console.log("processDataFromDatabase", error);
- }
-
- }
-
- }
- else {
- processingData = false;
- return;
- }
- }
-
- if (records.length > 0) {
- //clean backup file
- if (counter > 0) nosql.clean();
- }
-
- //no data in db, remove
- if (records.length == 0) {
- if (counter > 0) nosql.drop();
- }
-
- const d = new Date();
- lastRestoreTime = d.getTime();
-
- processingData = false;
-
- }
-
- instance.on('options', main);
-
-};
diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js
index d5f0842..48b4987 100644
--- a/flow/cmd_manager.js
+++ b/flow/cmd_manager.js
@@ -4,8 +4,13 @@ exports.group = 'Worksys';
exports.color = '#5D9CEC';
exports.version = '0.0.3';
exports.output = ['red', 'blue', 'yellow', 'blue', 'white'];
-exports.input = 3;
+
+//blue - send message to relays
+
+exports.input = true;
+exports.author = 'Daniel Segeš';
exports.icon = 'cloud-upload';
+//exports.npm = ['serialport' , 'child_process'];
exports.html = `
@@ -25,2771 +30,3764 @@ exports.html = `
`;
+
exports.readme = `Manager for CMD calls`;
+const SerialPort = require('serialport');
+const { exec } = require('child_process');
+const { crc8, crc16, crc32 } = require('easy-crc');
+const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js');
+const { bytesToInt, longToByteArray, addZeroBefore, isEmptyObject, convertUTCDateToLocalDate } = require('./helper/utils');
+const bitwise = require('bitwise');
+
+var SunCalc = require('./helper/suncalc.js');
+const DataToTbHandler = require('./helper/DataToTbHandler.js');
+const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
+const { promisifyBuilder, makeMapFromDbResult} = require('./helper/db_helper.js');
+const { sendNotification, initNotifications, ERRWEIGHT } = require('./helper/notification_reporter.js');
+
+const dbNodes = TABLE("nodes");
+const dbRelays = TABLE("relays");
+const dbSettings = TABLE("settings");
+
+//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
+//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
+var path = require('path');
+var log4js = require("log4js");
+const process = require('process');
+
+//TODO - to remove?
+// runTasks intervals
+const SHORT_INTERVAL = 30;
+const LONG_INTERVAL = 300;
+
+//send data to following instances:
+const SEND_TO = {
+ debug: 0,
+ tb: 1,
+ http_response: 2,
+ dido_controller: 3,
+ infoSender: 4
+}
+
+const PRIORITY_TYPES = {
+ terminal: 0,
+ fw_detection: 1,//reserved only for FW detection - FLOW.OMS_masterNodeIsResponding
+ high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
+ relay_profile: 3,
+ node_broadcast: 4,
+ node_profile: 5,
+ node_cmd: 6
+}
+
+//list of command calls to process. Processing in runTasks function
+let tasks = [];
+
+let interval = null;//timeout for procesing tasks
+let refFlowdata = null;//holds reference to httprequest flowdata
+let refFlowdataObj = {};
+
+//load from settings
+let latitude = 48.70826502;//48.682255758;
+let longitude = 17.28455203;//17.278910807;
+
+const gmtOffset = 0;
+
+//ak nie je nastaveny
+//https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
+//https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
+
+//priorities for registers
+let priorities = [];
+
+let minutes = 1;
+priorities["0"] = minutes;
+priorities["1"] = minutes;
+
+minutes = 5;
+priorities["74"] = minutes;
+priorities["75"] = minutes;
+priorities["76"] = minutes;
+priorities["77"] = minutes;
+priorities["78"] = minutes;
+priorities["79"] = minutes;
+priorities["84"] = minutes;
+
+minutes = 10;
+priorities["87"] = minutes;
+priorities["6"] = minutes;
+priorities["7"] = minutes;
+priorities["80"] = minutes;
+priorities["8"] = minutes;
+priorities["3"] = minutes;
+priorities["89"] = minutes;
+
+//prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
+let listOfCommands = [0,1,3,6,7,8,74,75,76,77,78,79,80,84,87,89];
+
+const errorHandler = new ErrorToServiceHandler();
+
+let rotary_switch_state = "Off";
+let lux_sensor;
+let state_of_breaker = {};//key is line, value is On/Off
+let disconnectedReport = {};//key is tbname, value true/false
+
+let relaysData = {};//key is line, value is data from db
+let nodesData = {};//key is node, value data from db
+
+//helper container for counting resolved group of commands (commands related to set profile)
+let cmdCounter = {};//key is node, value is counter
+let cmdNOKNodeCounter = {};//key is node, value is counter
+
+//END OF VARIABLE SETTINGS
+//--------------------------------
+
+
+log4js.configure({
+ appenders: {
+ errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
+ monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
+ console: { type: 'console' }
+ },
+ categories: {
+ errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
+ monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
+ //another: { appenders: ['console'], level: 'trace' },
+ default: { appenders: ['console'], level: 'trace' }
+ }
+});
+
+const errLogger = log4js.getLogger("errLogs");
+const logger = log4js.getLogger();
+const monitor = log4js.getLogger("monitorLogs");
+
+//USAGE
+//logger.debug("text")
+//monitor.info('info');
+//errLogger.error("some error");
+
+
+function cmdCounterResolve(address)
+{
+ if(cmdCounter.hasOwnProperty(address))
+ {
+ cmdCounter[address] = cmdCounter[address] - 1;
+
+ let result = cmdCounter[address];
+ if(result == 0) delete cmdCounter[address];
+ return result;
+ }
+ return -1;
+}
+
+
+function getParams(priority)
+{
+ let params = {};
+
+ //core rpc values
+ params.address = 0;//if(recipient === 0) address = 0;
+ params.byte1 = 0;//msb, podla dokumentacie data3
+ params.byte2 = 0;//podla dokumentacie data2
+ params.byte3 = 0;//podla dokumentacie data1
+ params.byte4 = 0;//lsb, podla dokumentacie data0
+ params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
+ params.register = -1;//register number
+ params.rw = 0;//0: read, 1: write
+
+ //other values
+ //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles" "edge_date_time" "number_of_luminaires"
+ //params.tbname = tbname;
+ params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
+ params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
+ if(priority != undefined )
+ {
+ params.timestamp = priority;
+ params.priority = priority;
+ }
+
+ params.addMinutesToTimestamp = 0;//repeat task if value is > 0,
+
+ //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
+ //params.info = "";
+
+ return params;
+}
+
+
+async function loadSettings()
+{
+ let responseSettings = await promisifyBuilder(dbSettings.find());
+
+ latitude = responseSettings[0]["latitude"];
+ longitude = responseSettings[0]["longitude"];
+
+ //globals
+ FLOW.OMS_language = responseSettings[0]["lang"];
+ FLOW.OMS_rvo_name = responseSettings[0]["rvo_name"];
+ FLOW.OMS_projects_id = responseSettings[0]["projects_id"];
+ //FLOW.OMS_rvo_tbname = responseSettings[0]["tbname"];
+ FLOW.OMS_temperature_adress = responseSettings[0]["temperature_adress"];
+ FLOW.OMS_controller_type = responseSettings[0]["controller_type"];
+ FLOW.OMS_serial_port = responseSettings[0]["serial_port"];
+
+ //logger.debug('settings', responseSettings[0]);
+
+ initNotifications();
+}
+
+loadSettings();
+
+
+async function loadNodes()
+{
+ const responseNodes = await promisifyBuilder(dbNodes.find());
+ nodesData = makeMapFromDbResult(responseNodes, "node");
+}
+
+loadNodes();
+
+
+//nastav profil nodu
+function processNodeProfile(node)
+{
+ if(rotary_switch_state != "Automatic")
+ {
+ logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
+ return;
+ }
+
+ let nodeObj = nodesData[node];
+ let line = nodeObj.line;
+
+ if(relaysData[line].contactor == 0)
+ {
+ logger.debug("line line is off", line, node);
+ return;
+ }
+
+ if(nodeObj.processed == 1)
+ {
+ logger.debug("node was already processed", node);
+ return;
+ }
+
+ let profile = nodeObj.profile;
+
+ logger.debug("processNodeProfile: start - set profile for ", node, profile);
+
+ let nodeProfile;
+ try{
+ nodeProfile = JSON.parse( profile );
+ if(Object.keys(nodeProfile).length === 0) throw ("profile is not defined");
+ } catch (error) {
+ logger.debug("Error parsing node profile", error);
+ }
+
+ logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
+
+ let timestamp = PRIORITY_TYPES.node_cmd;
+
+ removeTask({type: "set_node_profile", address: node});
+ cmdNOKNodeCounter[node] = 0;
+
+ //co ked sa prave spracovava?
+ //if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
+
+ if(nodeProfile === undefined)
+ {
+ //vypneme profil nodu, posleme cmd
+ //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
+ //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
+
+ logger.debug("turn off profile");
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'turn off/reset node profile';
+
+ cmdCounter[node] = 1;
+
+ tasks.push(params);
+
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.NOTICE, "Master node is working again", "", SEND_TO.tb, instance );
+ }
+ else
+ {
+ let tasksProfile = [];
+ //cmdCounter[node] = tasksProfile.length;
+ //tasks.push(tasksProfile);
+
+ //let timestamp = PRIORITY_TYPES.node_cmd;
+
+ //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;
+ params.byte4 = 96;
+ params.recipient = 1;
+ params.register = 8;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'turn off node profile';
+
+ tasksProfile.push(params);
+
+ timestamp++;
+
+ logger.debug("processNodeProfile: TS1 Time point a TS1 Time Point Levels ", node);
+
+ //TS1 Time point a TS1 Time Point Levels
+ let register = 9;
+ for(let i = 0; i < nodeProfile.intervals.length; i++)
+ {
+ let obj = nodeProfile.intervals[i];
+ //let timePoint = obj.time_point;
+ let dim_value = obj.value;
+
+
+ //Reg 9 až Reg 40
+
+ /*
+ Samotný profil sa zapisuje do max. 16 párov – časový bod a úroveň.
+ Prázdny profil je vtedy keď časový bod obsahuje hodnotu 0xFFFFFFFF (táto hodnota sa zapíše do registrov keď sa aktivuje reset profilu do registru 8).
+ Páry sa prechádzajú časovo zoradené takže teoreticky je jedno v akom poradí sa zapisujú ale je lepšie ich zapisovať v chronologickom poradí od 13:00.
+ Časový bod má formát:
+ Byte 3: hodiny Byte 2: minúty Byte 1: sekundy Byte 0 – rezervované
+ Register úrovne má rovnaký formát ako dimming register (Reg 1).
+ */
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //params.byte1 = 0;//msb, podla dokumentacie data3
+ //params.byte2 = 0;//podla dokumentacie data2
+ //params.byte3 = 0;//podla dokumentacie data1
+ //params.byte4 = 0;//lsb, podla dokumentacie data0
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ let start_time = obj.start_time;
+ let t = start_time.split(":");
+ //if(timePoint != undefined) t = timePoint.split(":");
+ //else t = [0,0];
+
+ logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = parseInt(t[0]);//hh
+ params.byte2 = parseInt(t[1]);//mm
+ params.byte3 = 0;//ss
+ params.byte4 = 0;//
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.byte1 = 0;
+ params.byte2 = 0;
+ params.byte3 = 0;//ss
+ params.byte4 = parseInt(dim_value) + 128;//
+ params.recipient = 1;
+ params.register = register;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = 'TS1 Time point Levels ' + (i + 1);
+
+ tasksProfile.push(params);
+
+ register++;
+ timestamp++;
+ }
+
+ //Threshold lux level for DUSK/DAWN
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //params.byte1 = 0;//msb, podla dokumentacie data3
+ //params.byte2 = 0;//podla dokumentacie data2
+ //params.byte3 = 0;//podla dokumentacie data1
+ //params.byte4 = 0;//lsb, podla dokumentacie data0
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+ //Time schedule settings na koniec
+ //if(nodeProfile.dusk_lux_sensor || nodeProfile.dawn_lux_sensor)
+ {
+
+ logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 96;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "Threshold lux level for DUSK/DAWN";
+
+ if(nodeProfile.dusk_lux_sensor)
+ {
+ let v = nodeProfile.dusk_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if(nodeProfile.dawn_lux_sensor)
+ {
+ let v = nodeProfile.dawn_lux_sensor_value;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //DUSK/DAWN max. adjust period
+ {
+
+ logger.debug("processNodeProfile: DUSK/DAWN max. adjust period", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 97;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "DUSK/DAWN max. adjust period";
+
+ if(nodeProfile.astro_clock)
+ {
+ let v = nodeProfile.dusk_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte1 = ba[1];//msb
+ params.byte2 = ba[0];
+ }
+
+ if(nodeProfile.astro_clock)
+ {
+ let v = nodeProfile.dawn_lux_sensor_time_window;
+ let ba = longToByteArray(v);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+
+ }
+
+ //Static offset
+ {
+
+ //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
+ //Bity 0 – 6: hodnota v minútach
+ //Bit 7: znamienko (1 – mínus)
+
+ logger.debug("processNodeProfile: Static offset", node);
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 98;
+ params.recipient = 1;
+ params.rw = 1;//write
+ params.timestamp = timestamp;
+ params.addMinutesToTimestamp = 0;
+ params.info = "Static offset";
+
+ if(nodeProfile.astro_clock)
+ {
+ let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
+ let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
+
+ if(dusk_astro_clock_offset < 0)
+ {
+ params.byte3 = (dusk_astro_clock_offset * -1) + 128;
+ }
+ else
+ {
+ params.byte3 = dusk_astro_clock_offset;
+ }
+
+ if(dawn_astro_clock_offset < 0)
+ {
+ params.byte4 = (dawn_astro_clock_offset * -1) + 128;
+ }
+ else
+ {
+ params.byte4 = dawn_astro_clock_offset;
+ }
+ }
+
+ tasksProfile.push(params);
+ timestamp++;
+ }
+
+ logger.debug("Time schedule settings - turn on", node);
+
+ params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "set_node_profile";
+ params.address = node;
+ params.register = 8;
+ params.recipient = 1;
+ params.rw = 1;//write
+
+
+
+ //Time schedule settings
+ let bits = [];
+
+ //Byte 0 (LSB):
+ //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
+ bits.push(1);
+ //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ if(nodeProfile.astro_clock == true)
+ {
+ //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
+ bits.push(0);
+
+ //Bity 6-7 - zatiaľ nepoužité
+ bits.push(0);
+ bits.push(0);
+
+ params.byte4 = bitwise.byte.write(bits.reverse());
+
+ //Byte 2 – nastavenie pre lux senzor:
+ bits = [];
+
+ //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if(nodeProfile.dusk_lux_sensor == true)//sumrak
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
+ if(nodeProfile.dawn_lux_sensor == true)//usvit
+ {
+ bits.push(1);
+ }
+ else bits.push(0);
+
+ //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
+ bits.push(0);//zatial neimplementovane
+
+ //Bit 3 – 7 - nepoužité
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+ bits.push(0);
+
+ params.byte2 = bitwise.byte.write(bits.reverse());
+ params.timestamp = timestamp;
+ params.info = "Time schedule settings - turn on";
+
+ tasksProfile.push(params);
+
+ //zaver
+ cmdCounter[node] = tasksProfile.length;
+
+ //tasks.push(tasksProfile);
+ tasks = tasks.concat(tasksProfile);
+
+ }
+
+ logger.debug("finished set profile for ", node);
+
+}
+
+
+function cleanUpRefFlowdataObj()
+{
+ let now = new Date();
+ let timestamp = now.getTime();
+
+ //clear old refFlowdata references
+ let keys = Object.keys(refFlowdataObj);
+ for(let i = 0; i < keys.length; i++)
+ {
+ let timestampKey = keys[i];
+
+ if((timestamp - timestampKey) > 60*1000 )
+ {
+ console.log("cleanUpRefFlowdataObj delete", timestampKey);
+ delete refFlowdataObj[ timestampKey ];
+ }
+ }
+}
+
+
+function removeTask(obj)
+{
+ let keys = Object.keys(obj);
+ tasks = tasks.filter((task) => {
+
+ let counter = 0;
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+ if(task.hasOwnProperty(key) && obj.hasOwnProperty(key))
+ {
+ if(task[key] == obj[key]) counter++;
+ }
+ }
+
+ if(counter == keys.length) return false;
+ return true;
+ });
+}
+
+
+
exports.install = function(instance) {
- const { SerialPort } = require('serialport');
- const { exec } = require('child_process');
- const { crc16 } = require('easy-crc');
- const { runSyncExec, writeData } = require('./helper/serialport_helper');
- const { bytesToInt, longToByteArray, addZeroBefore } = require('./helper/utils');
- const bitwise = require('bitwise');
-
- var SunCalc = require('./helper/suncalc');
- const DataToTbHandler = require('./helper/DataToTbHandler');
- const errorHandler = require('./helper/ErrorToServiceHandler');
- const { sendNotification } = require('./helper/notification_reporter');
- const process = require('process');
- const { errLogger, logger, monitor } = require('./helper/logger');
-
- //for accelerometer purposes
- const { naklony } = require("../databases/accelerometer_db");
-
- const dbNodes = TABLE("nodes");
- const dbRelays = TABLE("relays");
-
- let GLOBALS;
- let SETTINGS;
- let rsPort;
- let tbHandler;
-
- // runTasks intervals
- const SHORT_INTERVAL = 30;
- const LONG_INTERVAL = 300;
-
- //send data to following instances:
- const SEND_TO = {
- debug: 0,
- tb: 1,
- http_response: 2,
- dido_controller: 3,
- infoSender: 4
- }
-
- const PRIORITY_TYPES = {
- terminal: 0,
- fw_detection: 1,//reserved only for FW detection - SETTINGS.masterNodeIsResponding
- high_priority: 2,//reserverd only for: read dimming / brightness (after set dimming from platform)
- relay_profile: 3,
- node_broadcast: 4,
- node_profile: 5,
- node_cmd: 6
- }
-
- const TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION = 600000; // 10 minutes
-
- //list of command calls to process. Processing in runTasks function
- let tasks = [];
-
- let interval = null;//timeout for procesing tasks
- let customTasksInterval = null; // interval for reportEdgeDateTimeAndNumberOfLuminaires();
- let setCorrectTime = null; // interval for setting a correct edgeTime
- let sendNodeReadout = null; // interval for sending agregate data from node
-
- let refFlowdataObj = {};
-
- //load from settings
- let latitude = 48.70826502;//48.682255758;
- let longitude = 17.28455203;//17.278910807;
-
- const gmtOffset = 0;
-
- //ak nie je nastaveny
- //https://www.tecmint.com/set-time-timezone-and-synchronize-time-using-timedatectl-command/
- //https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates
-
- //priorities for registers
- let priorities = [];
-
- let minutes = 1;
- priorities["1"] = minutes;
- priorities["76"] = minutes;
-
- // minutes = 5;
- priorities["75"] = minutes;//current
- priorities["79"] = minutes;//energy
- priorities["87"] = minutes;//aktualny cas
- //priorities["84"] = minutes;
-
- // minutes = 10;
- priorities["74"] = minutes;
- priorities["77"] = minutes;
- priorities["78"] = minutes;
-
- // minutes = 60;
- priorities["0"] = minutes;
- priorities["6"] = minutes;
- priorities["7"] = minutes;
- priorities["8"] = minutes;
-
- // minutes = 60 * 24;
- priorities["89"] = minutes;
- priorities["80"] = minutes;
-
- //prikazy kt sa budu spustat na dany node - see config.js in terminal-oms.app. (1 - dimming)
- let listOfCommands = [0, 1, 6, 7, 8, 74, 75, 76, 77, 78, 79, 80, 87, 89];
-
- let rotary_switch_state;
- let lux_sensor;
- let state_of_breaker = {};//key is line, value is On/Off
- let disconnectedReport = {};//key is tbname, value true/false
-
- let relaysData;
- let nodesData;
-
- let sunCalcResult;
- let reportDuskDawn;
-
- //helper container for counting resolved group of commands (commands related to set profile)
- let cmdCounter = {};//key is node, value is counter
-
- //if sending of profile to node fails, we send notification and push node into set, so we do not send notification twice
- const nodeProfileSendFail = new Set();
-
- //we expect to get current temperature in Senica from senica-prod01
- let temperatureInSenica = null;
- let accelerometerInterval = null;
-
- //END OF VARIABLE SETTINGS
- //--------------------------------
-
-
- function main() {
- GLOBALS = FLOW.GLOBALS;
- SETTINGS = FLOW.GLOBALS.settings;
- relaysData = GLOBALS.relaysData;
- nodesData = GLOBALS.nodesData;
- latitude = GLOBALS.settings.latitude;
- longitude = GLOBALS.settings.longitude;
-
- tbHandler = new DataToTbHandler(SEND_TO.tb);
- tbHandler.setSender(exports.title);
-
- let now = new Date();
- console.log("CMD Manager installed", now.toLocaleString("sk-SK"));
-
- sunCalcResult = calculateDuskDawn();
-
- reportDuskDawn = {
- dusk_time: sunCalcResult.dusk_time,
- dawn_time: sunCalcResult.dawn_time,
- dusk_time_reported: undefined,
- dawn_time_reported: undefined
- };
-
- handleRsPort();
-
- customTasksInterval = setInterval(function() {
- reportEdgeDateTimeAndNumberOfLuminaires();
- }, 120000);
- reportEdgeDateTimeAndNumberOfLuminaires();
-
- setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
- setCorrectPlcTimeOnceADay();
-
- sendNodeReadout = setInterval(sendNodesData, 150000);
- accelerometerInterval = setInterval(accelerometerData, 60000 * 30); //30 min
- }
-
-
- function cmdCounterResolve(address) {
- if (cmdCounter.hasOwnProperty(address)) {
- cmdCounter[address] = cmdCounter[address] - 1;
-
- let result = cmdCounter[address];
- if (result == 0) delete cmdCounter[address];
- return result;
- }
- return -1;
- }
-
-
- function getParams(priority) {
- let params = {};
-
- //core rpc values
- params.address = 0;//if(recipient === 0) address = 0;
- params.byte1 = 0;//msb, podla dokumentacie data3
- params.byte2 = 0;//podla dokumentacie data2
- params.byte3 = 0;//podla dokumentacie data1
- params.byte4 = 0;//lsb, podla dokumentacie data0
- params.recipient = 0;//0: Master, 1: Slave, 2: Broadcast
- params.register = -1;//register number
- params.rw = 0;//0: read, 1: write
-
- //other values
- //params.type = "cmd"; "relay" "cmd-terminal" "set_node_profile" "process_profiles"
- //params.tbname = tbname;
- params.priority = PRIORITY_TYPES.node_cmd; //default priority - if more tasks with the same timestamp, we sort them based on priority
- params.timestamp = 0; //execution time - if timestamp < Date.now(), the task is processed
- if (priority != undefined) {
- params.timestamp = priority;
- params.priority = priority;
- }
-
- params.addMinutesToTimestamp = 0;//repeat task if value is > 0
- //if node regular readout does not respond, we repeat request
- params.repeatCounter = 0;
- //params.timePointName = "luxOff" // "luxOn", "dusk", "dawn", "profileTimepoint"
- //params.info = "";
- //params.debug = true; // will console.log params in writeData response
-
- return params;
- }
-
-
- //nastav profil nodu
- function processNodeProfile(node) {
- if (rotary_switch_state != "Automatic") {
- logger.debug("unable to process profile for node", node, "rotary_switch_state != Automatic");
- return;
- }
-
- let nodeObj = nodesData[node];
- let line = nodeObj.line;
-
- if (relaysData[line].contactor == 0) {
- logger.debug("line line is off", line, node);
- return;
- }
-
- if (nodeObj.processed == 1) {
- //logger.debug("node was already processed", node);
- return;
- }
-
- let nodeProfile = nodeObj.profile;
- logger.debug("processNodeProfile: start - set profile for ", node, nodeProfile);
- if (nodeProfile) {
-
- try {
- nodeProfile = JSON.parse(nodeProfile);
- } catch (error) {
- logger.debug("Cmd_manager - Error parsing node profile", error);
- }
-
- }
-
- logger.debug("processNodeProfile", node, line, nodeObj, nodeProfile);
-
- let timestamp = PRIORITY_TYPES.node_cmd;
-
- removeTask({ type: "set_node_profile", address: node });
-
- if (nodeProfile === "") {
- //vypneme profil nodu, posleme cmd
- //Pokiaľ je hodnota rovná 1 – Profil sa zapne, ostatné bity sa nezmenia.
- //Pokiaľ sa hodnota rovná 2 – profil sa vypne, ostatné bity sa nezmenia
-
- logger.debug("turn off profile");
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = 'turn off/reset node profile';
-
- cmdCounter[node] = 1;
-
- tasks.push(params);
- }
- else {
- let tasksProfile = [];
-
- //vypneme profil - Zapísať hodnotu 32 do registra Time Schedule Settings – reset profilu
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte4 = 96;
- params.recipient = 1;
- params.register = 8;
- params.rw = 1;//write
- params.timestamp = timestamp;
- 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).
- */
-
- let start_time = obj.start_time;
- let t = start_time.split(":");
- //if(timePoint != undefined) t = timePoint.split(":");
- //else t = [0,0];
-
- logger.debug("processNodeProfile: TS1 Time point ", (i + 1), node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.byte1 = parseInt(t[0]);//hh
- params.byte2 = parseInt(t[1]);//mm
- params.recipient = 1;
- params.register = register;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.addMinutesToTimestamp = 0;
- params.info = 'TS1 Time point ' + (i + 1);
-
- tasksProfile.push(params);
-
- register++;
- timestamp++;
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.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
- {
-
- logger.debug("processNodeProfile: Threshold lux level for DUSK/DAWN", node);
-
- let params = getParams();
- params.type = "set_node_profile";
- params.address = node;
- params.register = 96;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- 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();
- params.type = "set_node_profile";
- params.address = node;
- params.register = 97;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = "DUSK/DAWN max. adjust period";
-
- if (nodeProfile.astro_clock) {
- let v = nodeProfile.dusk_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte1 = ba[1];//msb
- params.byte2 = ba[0];
- }
-
- if (nodeProfile.astro_clock) {
- let v = nodeProfile.dawn_lux_sensor_time_window;
- let ba = longToByteArray(v);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- }
-
- tasksProfile.push(params);
- timestamp++;
-
- }
-
- //Static offset
- {
-
- //Statický offset pre časy úsvitu a súmraku. Byte 1 je pre DUSK, Byte 0 je pre DAWN. Formát:
- //Bity 0 – 6: hodnota v minútach
- //Bit 7: znamienko (1 – mínus)
-
- logger.debug("processNodeProfile: Static offset", node);
-
- let params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 98;
- params.recipient = 1;
- params.rw = 1;//write
- params.timestamp = timestamp;
- params.info = "Static offset";
-
- if (nodeProfile.astro_clock) {
- let dusk_astro_clock_offset = parseInt(nodeProfile.dusk_astro_clock_offset);
- let dawn_astro_clock_offset = parseInt(nodeProfile.dawn_astro_clock_offset);
-
- if (dusk_astro_clock_offset < 0) {
- params.byte3 = (dusk_astro_clock_offset * -1) + 128;
- }
- else {
- params.byte3 = dusk_astro_clock_offset;
- }
-
- if (dawn_astro_clock_offset < 0) {
- params.byte4 = (dawn_astro_clock_offset * -1) + 128;
- }
- else {
- params.byte4 = dawn_astro_clock_offset;
- }
- }
-
- tasksProfile.push(params);
- timestamp++;
- }
-
- logger.debug("Time schedule settings - turn on", node);
-
- params = getParams(PRIORITY_TYPES.node_cmd);
- params.type = "set_node_profile";
- params.address = node;
- params.register = 8;
- params.recipient = 1;
- params.rw = 1;//write
-
- //Time schedule settings
- let bits = [];
-
- //Byte 0 (LSB):
- //Bit 0 (LSB) – zapnutie/vypnutie profilov ako takých (1 – zapnuté).
- bits.push(1);
- //Bit 1 – 3 - zatiaľ nepoužité (zapisovať 0)
- bits.push(0);
- bits.push(0);
- bits.push(0);
- if (nodeProfile.astro_clock == true) {
- //Bit 4 – ak je nastavený profil sa riadi podľa astrohodín, a je 0 tak profil je jednoduchý
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 5 – zápis 1 spôsobí reset nastavení profilu (nastavenie prázdneho profilu)
- bits.push(0);
-
- //Bity 6-7 - zatiaľ nepoužité
- bits.push(0);
- bits.push(0);
-
- params.byte4 = bitwise.byte.write(bits.reverse());
-
- //Byte 2 – nastavenie pre lux senzor:
- bits = [];
-
- //Bit 0 (LSB) – riadenie súmraku podľa lux senzoru (1 – zapnuté). Súmrak sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if (nodeProfile.dusk_lux_sensor == true)//sumrak
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 1 - riadenie úsvitu podľa lux senzoru (1 – zapnuté). Úsvit sa môže posúvať v rámci času v registri 97 podľa intenzity osvetlenia
- if (nodeProfile.dawn_lux_sensor == true)//usvit
- {
- bits.push(1);
- }
- else bits.push(0);
-
- //Bit 2 – zdroj pre hodnotu luxov – 0 – RVO posiela hodnoty zo svojho luxmetra, 1 – node má pripojený svoj vlastný lux meter.
- bits.push(0);//zatial neimplementovane
-
- //Bit 3 – 7 - nepoužité
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
- bits.push(0);
-
- params.byte2 = bitwise.byte.write(bits.reverse());
- params.timestamp = timestamp;
- params.info = "Time schedule settings - turn on";
-
- tasksProfile.push(params);
-
- //zaver
- cmdCounter[node] = tasksProfile.length;
-
- //tasks.push(tasksProfile);
- tasks = tasks.concat(tasksProfile);
-
- }
-
- logger.debug("finished set profile for ", node);
-
- console.log("proces profile finished *********************")
- }
-
-
- function cleanUpRefFlowdataObj() {
- let now = new Date();
- let timestamp = now.getTime();
-
- //clear old refFlowdata references
- let keys = Object.keys(refFlowdataObj);
- for (let i = 0; i < keys.length; i++) {
- let timestampKey = keys[i];
-
- if ((timestamp - timestampKey) > 60 * 1000) {
- console.log("cleanUpRefFlowdataObj delete", timestampKey);
- delete refFlowdataObj[timestampKey];
- }
- }
- }
-
-
- function removeTask(obj) {
- let keys = Object.keys(obj);
- tasks = tasks.filter((task) => {
-
- let counter = 0;
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- if (task.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
- if (task[key] == obj[key]) counter++;
- }
- }
-
- if (counter == keys.length) return false;
- return true;
- });
- }
-
-
- process.on('uncaughtException', function(err) {
- //TODO send to service
-
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
-
- errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
- //process.exit(1);
- })
-
- //te();//force error
-
-
- function processAllNodeProfilesOnLine(line) {
- for (let k in nodesData) {
- if (line == nodesData[k].line) {
- let node = nodesData[k].node;
- let processed = nodesData[k].processed;
-
- if (!processed) processNodeProfile(node);
- //else logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
- }
- }
- }
-
-
- function loadRelaysData(line) {
- for (const [key, value] of Object.entries(relaysData)) {
- if (key == "0") continue;
- if (line != undefined) {
- //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
- if (line != value.line) continue;
- }
-
- if (value.contactor == 1) processAllNodeProfilesOnLine(value.line);
- }
- }
-
-
- function reportOnlineNodeStatus(line) {
- //Po zapnutí línie broadcastovo aktualizovať predtým čas a o 3 sek neskor - status, brightness
-
- logger.debug("Cmd-mngr: ----->reportOnlineNodeStatus for line", line);
-
- const d = new Date();
-
- // broadcast actual time
- let params = getParams();
- params.address = 0xffffffff;//Broadcast
- params.byte1 = d.getHours();
- params.byte2 = d.getMinutes();
- params.recipient = 2;//2 broadcast, address = 0
- params.register = 87;//Actual time
- params.rw = 1;//write
- params.type = "node-onetime-write";
- params.timestamp = d.getTime() + 30000;
- params.info = "run broadcast: Actual time";
- //params.debug = true;
-
- tasks.push(params);
-
- let sec = 3;
- setTimeout(function() {
- //Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
-
- let time = Date.now();
-
- 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;
- let status = "NOK";
-
- // if status of node was "OK" before switching it off, we set the node's time_of_last_communication on time, it was switched on again and send OK status to tb.
- if (nodesData[k].node_status_before_offline === true || nodesData[k].status === true) {
- status = "OK";
- nodesData[k].time_of_last_communication = time;
- }
-
- nodesData[k].readout.status = status;
-
- updateNodeStatus(k, status === "OK" ? true : false);
- if (nodesData[k].hasOwnProperty("node_status_before_offline")) delete nodesData[k].node_status_before_offline;
- sendTelemetry({ status: status }, tbname, time);
-
- //vyreportovanie dimming, current, input power pre liniu pre vsetky nody
- //Prud
- {
- let params = getParams();
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 75;//prud
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4000;
- params.info = 'read current';
- //params.debug = true;
- tasks.push(params);
- }
-
- //vykon
- {
- let params = getParams();
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 76;//výkon
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4100;
- params.info = 'read power';
- //params.debug = true;
-
- tasks.push(params);
- }
- //dimming
- {
- let params = getParams();
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;//dimming
- params.recipient = 1;//slave
- params.rw = 0;//read
- params.timestamp = time + 4200;
- params.info = 'read dimming';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- }
- }
-
- }, sec * 1000);
- }
-
-
- function reportOfflineNodeStatus(line) {
-
- logger.debug("Cmd-mngr: ------>reportOfflineNodeStatus for line", line);
-
- values = {};
- values["dimming"] = 0;//brightness
- values["power"] = 0;//výkon
- values["current"] = 0;//prúd
- values["status"] = "OFFLINE";
-
- const date = Date.now();
-
- Object.keys(nodesData).forEach(node => {
-
- //potrebujem nody k danej linii
- if (line == nodesData[node].line || line == undefined) {
-
- let tbname = nodesData[node].tbname;
- let nodeStatus = nodesData[node].status;
-
- //in case we have reported offline node status, we return (continue with next node)
- if (nodeStatus === "OFFLINE") return;
-
- nodesData[node].node_status_before_offline = nodeStatus;
- nodesData[node].status = "OFFLINE";
- nodesData[node].readout = {};
-
- sendTelemetry({ ...values }, tbname, date);
- }
- })
-
- }
-
-
- function turnLine(onOrOff, line, info) {
- let obj = {
- line: line,
- command: onOrOff,
- info: info
- };
-
- //logger.debug("linia", line, obj);
- instance.send(SEND_TO.dido_controller, obj);
- }
-
-
-
- function detectIfResponseIsValid(bytes) {
- //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
- let type = "RESPONSE";
- if (bytes.length == 1) type = "BROADCAST"; // odpoved z rsPortu na broadcast command: ["broadcast"]
- else if (bytes[4] == 0) type = "RESPONSE";
- else if (bytes[4] == 1) type = "ERROR";
- else if (bytes[4] == 2) type = "EVENT";
- else type = "UNKNOWN";
-
- let message = "OK";
- let error = "";
- if (type == "BROADCAST") return { message, type, error };
-
- let crc = crc16('ARC', bytes.slice(0, 9));
- let c1 = (crc >> 8) & 0xFF;
- let c2 = crc & 0xFF;
-
- if (c1 != bytes[9]) {
- //CRC_ERROR
- message = "NOK";
- error = "CRC_ERROR c1";
- instance.send(SEND_TO.debug, "CRC_ERROR c1");
- }
-
- if (c2 != bytes[10]) {
- //CRC_ERROR
- message = "NOK";
- error = "CRC_ERROR c2";
- instance.send(SEND_TO.debug, "CRC_ERROR c2");
- }
-
- //crc error
- if (type != "RESPONSE") {
- instance.send(SEND_TO.debug, bytes);
- instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]);
-
- //logger.debug(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4], bytes);
-
- error = "type is: " + type;
-
- message = "NOK";
- }
-
- return { message, type, error };
- }
-
-
- //BUILD TASKS//
- function buildTasks(params) {
-
- //return;
- console.log("buidTAaasks start ****************", params);
- 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;
- }
-
- let now = new Date();
-
- //process line profiles
- if (processLineProfiles) {
-
- let keys = Object.keys(relaysData);
-
- for (let i = 0; i < keys.length; i++) {
-
- let line = parseInt(keys[i]);
- let profilestr = relaysData[line].profile;
-
- if (processLine != undefined) {
- if (processLine != line) continue;
- }
-
- try {
-
- /**
- * we process line profiles: timepoints, astro clock, lux_sensor, offsets ...
- */
- if (profilestr === "") throw ("Profile is not defined");
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("Profile is empty");
-
- monitor.info("buildTasks: profile for line", line);
- monitor.info("profile:", profile);
-
- let time_points = profile.intervals;
-
- // add name to regular profile timepoint and delete unused end_time key:
- time_points.forEach(point => {
- point.name = "profileTimepoint"
- delete point.end_time;
- });
-
- //monitor.info("buildTasks: time_points", time_points);
-
-
- /**
- * if astro_clock is true, we create timepoints, that switch on/off relays accordingly.
- * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn
- * if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching
- */
- if (profile.astro_clock == true) {
-
- // if astro clock true, we remove all regular profile points
- time_points = [];
-
- let sunCalcResult = calculateDuskDawn(new Date(), line);
-
- // adding dusk dawn to timpoints
- if (profile.dawn_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dawn"], "value": 0, "name": "dawn" });
- if (profile.dusk_lux_sensor == false) time_points.push({ "start_time": sunCalcResult["dusk"], "value": 1, "name": "dusk" });
-
- //if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit)
- //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
- if (profile.dawn_lux_sensor == true) {
- let [ahours, aminutes] = sunCalcResult["dawn"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dawn_lux_sensor_time_window, 0);
-
- let strDate = ad.getHours() + ":" + ad.getMinutes();
- time_points.push({ "value": 0, "start_time": strDate, "name": "luxOff" });
- }
-
- if (profile.dusk_lux_sensor == true) {
- let [ahours, aminutes] = sunCalcResult["dusk"].split(':');
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes) + profile.dusk_lux_sensor_time_window, 0);
-
- let strDate = ad.getHours() + ":" + ad.getMinutes();
- time_points.push({ "value": 1, "start_time": strDate, "name": "luxOn" });
- //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
- }
- }
-
- //sort time_points
- time_points.sort(function(a, b) {
-
- let [ahours, aminutes] = a.start_time.split(':');
- let [bhours, bminutes] = b.start_time.split(':');
-
- let ad = new Date();
- ad.setHours(parseInt(ahours), parseInt(aminutes), 0);
-
- let bd = new Date();
- bd.setHours(parseInt(bhours), parseInt(bminutes), 0);
-
- return ad.getTime() - bd.getTime();
- });
-
- console.log("line timepoints ........", time_points);
-
- let currentValue = 0;
- if (time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
-
- monitor.info("-->comming events turn on/off lines:");
- for (let t = 0; t < time_points.length; t++) {
-
- let start_time = new Date();
- let [hours, minutes] = time_points[t].start_time.split(':');
- start_time.setHours(parseInt(hours), parseInt(minutes), 0);
-
- //task is in the past
- if (now.getTime() > start_time.getTime()) {
- currentValue = time_points[t].value;
-
- //timepoint is in past, we add 24 hours
- start_time.setDate(start_time.getDate() + 1);
- }
-
- let params = getParams();
- params.type = "relay";
- params.line = parseInt(line);
- params.value = time_points[t].value;
- params.tbname = relaysData[line].tbname;
- params.timestamp = start_time.getTime();
-
- // it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day
- if (time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24 * 60;
-
- //astro timepoints will be recalculated dynamically:
- params.timePointName = time_points[t].name;
-
- // if astro timepoint, we save time window:
- if (['luxOn', 'luxOff', 'dusk', 'dawn'].includes(params.timePointName)) {
- params.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window;
- params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window;
- }
-
- if (params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
- else if (params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
-
- params.debug = true;
-
- //turn on/off line
- tasks.push(params);
- monitor.info("TimePoint params: ", params.info, start_time);
- }
-
- monitor.info("-->time_points final", line, time_points);
-
- //ensure to turn on/off according to calculated currentValue
- let params = getParams();
- params.type = "relay";
- params.line = parseInt(line);
- params.tbname = relaysData[line].tbname;
- params.value = currentValue;
- params.timestamp = i;
- 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);
- console.log(`Cmd_manager: Unable to process line profile ${line}. Error: `, error);
- errorHandler.sendMessageToService(profilestr + "-" + error, 0, "js_error");
- } else {
- turnLine("off", line, "No line profile. Switching it off on startup");
- }
- }
-
- }
- //logger.debug("tasks:");
- //logger.debug(tasks);
- }
-
-
- //NOTE: PROCESS DEFAULT BROADCASTS - Time of dusk, Time of dawn, Actual Time
- if (processBroadcast) {
-
- let d = new Date();
- let time = d.getTime();
- let sunCalcResult = calculateDuskDawn();
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = sunCalcResult["dusk_hours"];
- params.byte2 = sunCalcResult["dusk_minutes"];
- params.recipient = 2;//2 broadcast,
- params.register = 6;//Time of dusk
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60000;
- params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dusk
- params.info = "Broadcast-duskTime";
-
- tasks.push(params);
- }
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = sunCalcResult["dawn_hours"];
- params.byte2 = sunCalcResult["dawn_minutes"];
- params.recipient = 2; //2 broadcast
- params.register = 7;//Time of dawn
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60001;
- params.addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
- params.info = "Broadcast-dawnTime";
-
- tasks.push(params);
- }
-
- {
- let params = getParams();
-
- params.address = 0xffffffff;//broadcast
- params.byte1 = d.getHours();
- params.byte2 = d.getMinutes();
- params.recipient = 2; //2 broadcast
- params.register = 87;//Actual time
- params.rw = 1;//write
- params.type = "node-regular-write";
- params.timestamp = time + 60002;
- params.addMinutesToTimestamp = 5;
- params.info = "run broadcast: Actual time";
-
- tasks.push(params);
- }
-
- }
-
- //process nodes & tasks - read node's data
- if (processNodes) {
-
- let time = Date.now();
-
- for (let k in nodesData) {
- let address = parseInt(k);
- let tbname = nodesData[k].tbname;
- let register = 0;
-
- for (let i = 0; i < listOfCommands.length; i++) {
-
- register = listOfCommands[i];
- let addMinutesToTimestamp = priorities[register];
-
- let params = getParams();
-
- params.address = address;
- params.recipient = 1;
- params.register = register;
- params.type = register == 1 ? "node-dimming-read" : "node-regular-read";
- params.tbname = tbname;
- params.timestamp = time + 5000 + i * 500 + addMinutesToTimestamp * 1000; //to make slight time difference
- params.addMinutesToTimestamp = addMinutesToTimestamp;
- params.info = "Node regular read command";
-
- tasks.push(params);
- }
-
- }
- }
-
-
- //niektore ulohy sa vygeneruju iba 1x pri starte!!!
- if (!init) return;
-
-
- //Master node FW version - modifies SETTINGS.masterNodeIsResponding
- {
- let params = getParams();
- params.type = "cmd-master";
- params.register = 4;
- params.address = 0;
- params.timestamp = 0;
- params.addMinutesToTimestamp = 5;
- params.tbname = SETTINGS.rvoTbName;
- params.info = "Master node FW verzia";
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //kazdu hodinu skontrolovat nastavenie profilov
- {
- let params = getParams();
- params.type = "process_profiles";
- params.timestamp = Date.now() + 60001;
- params.addMinutesToTimestamp = 60;//60 = every hour
- params.info = "detekcia nespracovaných profilov linie a nodov";
- //params.debug = true;
-
- tasks.push(params);
- }
-
- monitor.info("tasks created:", tasks.length);
- }
-
-
- /**
- * We process line profile, where "astro_clock": true
- * example profile:
- *
- "dawn_lux_sensor": true,
- "dusk_lux_sensor": true,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 0,
- "dusk_astro_clock_offset": 10,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
+ let now = new Date();
+ console.log("CMD Manager installed", now.toLocaleString("sk-SK"));
+
+ const tbHandler = new DataToTbHandler(SEND_TO.tb);
+ tbHandler.setSender(exports.title);
+
+ //FLOW.OMS_projects_id, name: FLOW.OMS_rvo_name
+ //const errorHandler = new ErrorToServiceHandler(instance, SEND_TO.infoSender);
+ errorHandler.setProjectsId(FLOW.OMS_projects_id);
+ //const errorHandler = new ErrorToServiceHandler(instance);
+ //errorHandler.sendMessageToService("ahoj", 0);
+
+ let sunCalcResult = calculateDuskDawn();
+
+ let reportDuskDawn = {
+ dusk_time: sunCalcResult.dusk_time,
+ dawn_time: sunCalcResult.dawn_time,
+ dusk_time_reported: undefined,
+ dawn_time_reported: undefined
+ };
+
+
+ process.on('uncaughtException', function (err) {
+
+ //TODO send to service
+
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
+
+ errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
+ //process.exit(1);
+ })
+
+ //te();//force error
+
+
+ function processAllNodeProfilesOnLine(line)
+ {
+
+ for (let k in nodesData) {
+ //node:number|tbname:string|line:number|profile:string|processed:boolean
+
+ if(line == nodesData[k].line)
+ {
+ let node = nodesData[k].node;
+ let processed = nodesData[k].processed;
+
+ if(!processed)
+ {
+ processNodeProfile(node);
+ }
+ else
+ {
+ logger.debug( `Node ${node} profile for line ${nodesData[k].line} was already processed`);
+ }
+ }
+ }
+ }
+
+
+ async function loadRelaysData(line) {
+
+ relaysData = await promisifyBuilder(dbRelays.find());
+ relaysData = makeMapFromDbResult(relaysData, "line");
+
+ for (const [key, value] of Object.entries(relaysData))
+ {
+ if(key == "0") continue;
+ if(line != undefined)
+ {
+ //ak sa jedna o update profilu linie - pozor dido_controller posiela command pre loadRelaysData
+ if(line != value.line ) continue;
+ }
+
+ if(value.contactor == 1) processAllNodeProfilesOnLine(value.line);
+ }
+
+// console.log('.........', relaysData);
+ }
+
+
+ function reportOnlineNodeStatus(line)
+ {
+ //broadcast cas, o 3 sek neskor - status, brightness
+ //Po zapnutí línie broadcastovo aktualizovať predtým čas.
+
+ logger.debug("--->reportOnlineNodeStatus for line", line);
+
+ //return;
+
+ //run broadcast //Actual time
+ addMinutesToTimestamp = 0;
+
+ let params = {};
+
+ let recipient = 2;//2 broadcast, address = 0
+ let address = 0;//0
+ if(recipient === 2)
+ {
+ address = 0xffffffff;//Broadcast
+ }
+
+ var d = new Date();
+ let hours = d.getHours();
+ let minutes = d.getMinutes();
+ let seconds = d.getSeconds();
+
+ params.address = address;//broadcast
+ params.byte1 = hours;//h
+ params.byte2 = minutes;//m
+ params.byte3 = seconds;//s
+ params.byte4 = 0;
+ params.recipient = recipient;
+ params.register = 87;//Actual time
+ params.rw = 1;//write
+
+ let timestampStart = PRIORITY_TYPES.node_broadcast;
+
+ //other values
+ params.type = "cmd";
+ //params.tbname = tbname;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = addMinutesToTimestamp;
+ params.info = "run broadcast: Actual time";
+
+ tasks.push(params);
+
+ let sec = 3;
+ setTimeout(function(){
+ //Po zapnutí línie - spraviť hromadný refresh stavu práve zapnutých svietidiel
+
+ for (let k in nodesData) {
+
+ //potrebujem nody k danej linii
+ if(line == nodesData[k].line || line == undefined)
+ {
+ let tbname = nodesData[k].tbname;
+ let node = nodesData[k].node;
+
+ //prud, vykon - current, input power pre liniu pre vsetky nody
+
+ //a pridame aj vyreportovanie dimmingu
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;//dimming
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read dimming';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //Prúd
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 75;//prud
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read current';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //výkon
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 76;//výkon
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read power';
+ //params.debug = true;
+
+ tasks.push(params);
+ }
+ }
+ }
+ },sec*1000);
+ }
+
+
+ function reportOfflineNodeStatus(line)
+ {
+ logger.debug("--->reportOfflineNodeStatus for line", line);
+
+ values = {};
+ 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(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+ }
+ }
+
+ //report OFFLINE for line
+ //relaysData[line].tbname;
+
+ //values = {};
+ //values["status"] = "OFFLINE";//prúd
+ }
+
+
+ function turnOnLine(line, info)
+ {
+ let obj = {
+ line: line,
+ command: "turnOn",
+ info: info
+ };
+
+ logger.debug("linia", line, obj);
+ instance.send(SEND_TO.dido_controller, obj);
+ }
+
+ function turnOffLine(line, info)
+ {
+ let obj = {
+ line: line,
+ command: "turnOff",
+ info: info
+ };
+
+ logger.debug("linia", line, obj);
+ instance.send(SEND_TO.dido_controller, obj);
+ }
+
+
+ function detectIfResponseIsValid(bytes)
+ {
+ //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
+ let type = "RESPONSE";
+ if(bytes[4] == 0) type = "RESPONSE";
+ else if(bytes[4] == 1) type = "ERROR";
+ 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(SEND_TO.debug, "CRC_ERROR c1");
+ }
+
+ if(c2 != bytes[10])
+ {
+ //CRC_ERROR
+ message = "NOK";
+ error = "CRC_ERROR c2";
+ instance.send(SEND_TO.debug, "CRC_ERROR c2");
+ }
+
+ //crc error
+ if(type != "RESPONSE")
+ {
+ instance.send(SEND_TO.debug, bytes);
+ instance.send(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4]);
+
+ //logger.debug(SEND_TO.debug, "RESPONSE " + type + " - " + bytes[4], bytes);
+
+ error = "type is: " + type;
+
+ message = "NOK";
+ }
+
+ return {message: message, type: type, error: error};
+ }
+
+
+ //BUILD TASKS//
+ function buildTasks(params)
+ {
+ //report FLOW.OMS_edge_fw_version as fw_version
+ //report date as startdate
+
+ //return;
+
+ 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 = parseInt(keys[i]); //line is turned off by default
+ let profilestr = relaysData[line].profile;
+
+ if(processLine != undefined)
+ {
+ if(processLine != line) continue;
+ }
+
+ try {
+
+ /**
+ * we process line profiles: timepoints, astro clock, lux_sensor, offsets ...
+ */
+ if(profilestr === "") throw ("Profile is not defined");
+ let profile = JSON.parse(profilestr);
+ if(Object.keys(profile).length === 0) throw ("Profile is empty");
+
+ 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;
+
+ // add name to regular profile timepoint and delete unused end_time key:
+ time_points.forEach(point => {
+ point.name = "profileTimepoint"
+ delete point.end_time;
+ });
+
+ //monitor.info("buildTasks: time_points", time_points);
+
+ let currentValue = 0;
+ if(time_points.length > 0) currentValue = time_points[time_points.length - 1].value;
+
+
+ /**
+ * if astro_clock is true, we create timepoints, that switch on/off relays accordingly.
+ * we need to manage, astro clock timepoints has the greatest priority - normal timepoints will not switch off/on lines before dusk or dawn
+ * if dawn/dusk_lux_sensor is true, it has higher priority than astro_clock switching
+ */
+ if(profile.astro_clock == true)
+ {
+
+ // if astro clock true, we remove all regular profile points
+ time_points = [];
+
+ let sunCalcResult = calculateDuskDawn(new Date(), line);
+
+ // adding dusk dawn to timpoints
+ if(profile.dawn_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dawn"], "value": 0, "name":"dawn"});
+ if(profile.dusk_lux_sensor == false) time_points.push({"start_time": sunCalcResult["dusk"], "value": 1, "name":"dusk"});
+
+ //if dusk/dawn is true, lines will switch on/off according to lux_sensor value. In case it fails, we create lux_timepoints, to make sure lines will switch on/off (aby nam to nezostalo svietit)
+ //force to turn off after timestamp: dawn + dawn_lux_sensor_time_window
+ if(profile.dawn_lux_sensor == true)
+ {
+ let [ahours, aminutes, aseconds] = sunCalcResult["dawn"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours));
+ ad.setMinutes(parseInt(aminutes) + profile.dawn_lux_sensor_time_window);
+ ad.setSeconds(0);
+
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+
+ time_points.push({"value": 0, "start_time": strDate, "name": "luxOff"});
+ }
+
+ if(profile.dusk_lux_sensor == true)
+ {
+ let [ahours, aminutes, aseconds] = sunCalcResult["dusk"].split(':');
+ let ad = new Date();
+ ad.setHours(parseInt(ahours));
+ ad.setMinutes(parseInt(aminutes) + profile.dusk_lux_sensor_time_window);
+ ad.setSeconds(0);
+
+ let strDate = ad.getHours() + ":" + ad.getMinutes();
+
+ time_points.push({"value": 1, "start_time": strDate, "name": "luxOn"});
+ //time_points.push({"value": 1, "start_time": "15:19", "name": "luxOn"}); //testing
+ }
+ }
+
+ //sort time_points
+ time_points.sort(function (a, b) {
+
+ 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("line timepoints ........", time_points);
+
+ monitor.info("-->comming events turn on/off lines:");
+ for(let t = 0; t < time_points.length; t++)
+ {
+
+ let start_time = new Date();
+ let [hours, minutes, seconds] = time_points[t].start_time.split(':');
+
+ 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;
+
+ //timepoint is in past, we add 24 hours
+ start_time.setDate(start_time.getDate() + 1);
+ }
+
+ let params = getParams(PRIORITY_TYPES.relay_profile);
+ params.type = "relay";
+ params.line = parseInt(line);
+ params.value = time_points[t].value;
+ params.tbname = relaysData[line].tbname;
+ params.timestamp = start_time.getTime();
+
+ params.addMinutesToTimestamp = 0;
+
+ // it timepoints are not calculated (dawn, dusk, lux_timepoint), but static points in line profile, we just repeat the task every day
+ if(time_points[t].name == "profileTimepoint") params.addMinutesToTimestamp = 24*60;
+
+ //astro timepoints will be recalculated dynamically:
+ params.timePointName = time_points[t].name;
+
+ // if astro timepoint, we save time window:
+ if(['luxOn', 'luxOff', 'dusk','dawn'].includes(params.timePointName))
+ {
+ params.dawn_lux_sensor_time_window = profile.dawn_lux_sensor_time_window;
+ params.dusk_lux_sensor_time_window = profile.dusk_lux_sensor_time_window;
+ }
+
+ if(params.value == 0) params.info = `${params.timePointName}: turn off line: ` + line;
+ else if(params.value == 1) params.info = `${params.timePointName}: turn on line: ` + line;
+
+ params.debug = true;
+
+ //turn on/off line
+ tasks.push(params);
+ monitor.info(params.info, start_time);
+
+ }
+
+ monitor.info("-->time_points final", line, time_points);
+
+ //ensure to turn on/off according to calculated value
+ let params = getParams(PRIORITY_TYPES.terminal);
+ params.type = "relay";
+ params.line = parseInt(line);
+ params.tbname = relaysData[line].tbname;
+ params.value = currentValue;
+
+ params.timestamp = PRIORITY_TYPES.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 * 3; //kazde 3 hodiny zisti novy dusk
+
+ let params = getParams(PRIORITY_TYPES.node_broadcast);
+
+ let sunCalcResult = calculateDuskDawn();
+ let dusk_hours = sunCalcResult["dusk_hours"];
+ let dusk_minutes = sunCalcResult["dusk_minutes"];
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = dusk_hours;//h
+ params.byte2 = dusk_minutes;//m
+ params.byte3 = 0;//s
+ params.byte4 = 0;
+ params.recipient = 2;//2 broadcast,
+ params.register = 6;//Time of dusk - Reg 6
+ params.rw = 1;//write
+
+ let timestampStart = PRIORITY_TYPES.node_broadcast;
+
+ //other values
+ params.type = "cmd";
+ //params.tbname = tbname;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = addMinutesToTimestamp;
+ params.info = "Broadcast-duskTime";
+
+ tasks.push(params);
+
+ }
+
+ {
+
+ //run broadcast Time of dawn
+ // addMinutesToTimestamp = 60*5;
+ addMinutesToTimestamp = 60 * 3; //kazde 3 hodiny zisti novy dawn
+
+ let params = getParams(PRIORITY_TYPES.node_broadcast);
+
+ let sunCalcResult = calculateDuskDawn();
+ let dawn_hours = sunCalcResult["dawn_hours"];
+ let dawn_minutes = sunCalcResult["dawn_minutes"];
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = dawn_hours;//h
+ params.byte2 = dawn_minutes;//m
+ params.byte3 = 0;//s
+ params.byte4 = 0;
+ params.recipient = 2; //2 broadcast
+ params.register = 7;//Time of dawn - Reg 6
+ params.rw = 1;//write
+
+ let timestampStart = PRIORITY_TYPES.node_broadcast;
+
+ //other values
+ params.type = "cmd";
+ //params.tbname = tbname;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = addMinutesToTimestamp;
+ params.info = "Broadcast-dawnTime";
+
+ tasks.push(params);
+ }
+
+ {
+ //run broadcast //Actual time
+ addMinutesToTimestamp = 5;
+
+ let params = getParams(PRIORITY_TYPES.node_broadcast);
+
+ var d = new Date();
+ let hours = d.getHours();
+ let minutes = d.getMinutes();
+ let seconds = d.getSeconds();
+
+ params.address = 0xffffffff;//broadcast
+ params.byte1 = hours;//h
+ params.byte2 = minutes;//m
+ params.byte3 = seconds;//s
+ params.byte4 = 0;
+ params.recipient = 2; //2 broadcast
+ params.register = 87;//Actual time
+ params.rw = 1;//write
+
+ let timestampStart = PRIORITY_TYPES.node_broadcast;
+
+ //other values
+ params.type = "cmd";
+ //params.tbname = tbname;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = addMinutesToTimestamp;
+ params.info = "run broadcast: Actual time";
+
+ tasks.push(params);
+ }
+
+ }
+
+ //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(PRIORITY_TYPES.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 = PRIORITY_TYPES.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(PRIORITY_TYPES.fw_detection);
+ params.type = "cmd";
+ params.register = 4;
+ params.address = 0;
+
+ let timestampStart = PRIORITY_TYPES.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
- * if dawn: if currentTimestamp is in timewindow "dawnTime + and - dawn_lux_sensor_time_window" and lux value >= lux_sensor_value, we switch off the line.
- * if dusk: we do oposite
- *
- * dawn: usvit - lux je nad hranicou - vypnem
- * dusk: sumrak - lux je pod hranicou - zapnem
- */
- function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value) {
-
- let 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;
- const contactor = relaysData[line].contactor;
-
- try {
-
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
-
- if (profile.astro_clock == true) {
- let sunCalcResult = calculateDuskDawn(now, line);
-
- //usvit
- if (profile.dawn_lux_sensor == true) {
- let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
- let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt(profile.dawn_lux_sensor_time_window) * 1000 * 60);
-
- if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
- if (lux_sensor_value > profile.dawn_lux_sensor_value) {
- if (contactor) turnLine("off", line, "Profile: dawn - turnOff line according to lux sensor");
- }
- }
- }
-
- //sumrak
- if (profile.dusk_lux_sensor == true) {
- let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
- let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt(profile.dusk_lux_sensor_time_window) * 1000 * 60);
-
- if (currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2) {
- if (lux_sensor_value < profile.dusk_lux_sensor_value) {
- if (!contactor) turnLine("on", line, "Profile: dusk - turnOn line according to lux sensor");
- }
- }
- }
-
- }
-
- } catch (error) {
- if (profilestr !== "") monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
- }
-
- }
-
- }
-
- /**
- * function updates status and time_of_last_communication of node in the dbNodes
- * it only updates if conditions are met
- * it only updates time_of_last_communication of node, if the last written time was more than 10 minutes ago (600000 miliseconds)
- * if newStatus of node is always receiving false, and it is already for more than SETTINGS.node_status_nok_time value, we update status to "NOK" in tb
- * function returns true, if status of node needs to be updated in TB (newStatus attribute is false in this case).
- */
- function updateNodeStatus(node, newStatus) {
- //MASTER
- if (node == 0) return;
-
- let nodeObj = nodesData[node];
- if (nodeObj == undefined) return;
-
- let nodeCurrentStatus = nodeObj.status;
- const now = Date.now();
-
- let data = null;
-
- if (nodeCurrentStatus === "OFFLINE") {
- data = { status: newStatus };
- nodeDbStatusModify(node, data);
- return;
- }
- else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication > now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) return;
- else if (newStatus == true && nodeCurrentStatus == true && nodeObj.time_of_last_communication < now - TIME_AFTER_WE_UPDATE_LAST_NODE_COMMUNICATION) {
- data = { time_of_last_communication: now };
- nodeDbStatusModify(node, data);
- return;
- }
- else if (newStatus == false && nodeCurrentStatus == false) return true;
- else if (newStatus == false && nodeCurrentStatus == true) {
- if (nodeObj.time_of_last_communication + SETTINGS.node_status_nok_time > now) return;
- else {
- data = { status: newStatus };
- nodeDbStatusModify(node, data);
- return true;
- }
- }
- else if (newStatus == true && nodeCurrentStatus == false) {
- data = { status: newStatus, time_of_last_communication: now };
- nodeDbStatusModify(node, data);
- return;
- }
-
- }
-
-
- function nodeDbStatusModify(node, data) {
- dbNodes.modify(data).where("node", node).callback(function(err, response) {
- if (!err) {
- nodesData[node] = { ...nodesData[node], ...data };
- }
- });
- }
-
-
- 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", SETTINGS.rvoTbName, "dusk_has_occured", { value: sunCalcResult["dusk"] }, "", SEND_TO.tb, instance);
- reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
- }
- }
-
- var nextDay = new Date();
- nextDay.setDate(nextDay.getDate() + 1);
-
- sunCalcResult = calculateDuskDawn(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", SETTINGS.rvoTbName, "dawn_has_occured", { value: sunCalcResult["dawn"] }, "", SEND_TO.tb, instance);
- reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
- }
- }
-
- var nextDay = new Date();
- nextDay.setDate(nextDay.getDate() + 1);
-
- sunCalcResult = calculateDuskDawn(nextDay);
- reportDuskDawn.dawn_time = sunCalcResult.dawn_time;
-
- }
- //--------------------------------------------------------
-
- //sort tasks based on timestamp
- tasks.sort(function(a, b) {
- if (a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp) {
- return a.priority - b.priority;
- }
- return a.timestamp - b.timestamp;
- });
-
- if (tasks.length == 0) {
- instance.send(SEND_TO.debug, "no tasks created");
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- if (!rsPort.isOpen) {
- instance.send(SEND_TO.debug, "!rsPort.isOpen");
- //await rsPort.open();
- //console.log("Cmd_manager - !rsPort.isOpen");
- }
-
- let currentTask = tasks[0];
-
- if (currentTask.debug) {
- //logger.debug("--->task to process", currentTask);
- }
-
- if (currentTask.timestamp <= currentTimestamp) {
- let params = { ...tasks[0] };
-
- //allow terminal commands
- if (SETTINGS.maintenance_mode && params.type !== "cmd-terminal") {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- let type = params.type;
- let tbname = params.tbname;
- let node = params.address;
-
- let register = params.register;
- let line = null;
- let itIsNodeCommand;
-
- if (nodesData[node] !== undefined) {
- line = nodesData[node].line;
- itIsNodeCommand = true;
- }
-
- if (params.line !== undefined) line = params.line;
-
- if (params.addMinutesToTimestamp > 0 || params.timePointName) {
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
- } else {
- tasks.shift();
- }
-
- //kontrola nespracovanych profilov nodov
- if (type == "process_profiles") {
- //na vsetky zapnutych liniach sa spracuju nespracovane profily nodov
- loadRelaysData();
- interval = setInterval(runTasks, SHORT_INTERVAL);
- return;
- }
-
- //relay
- if (type == "relay") {
-
- const timePointName = params.timePointName;
- const value = params.value;
-
- let date = new Date();
- date.setDate(date.getDate() + 1);//next day
-
- let sunCalcResult;
- if (timePointName) sunCalcResult = calculateDuskDawn(date, params.line);
-
- if (timePointName == "dawn") {
- tasks[0].timestamp = sunCalcResult.dawn_time;
- }
- else if (timePointName == "dusk") {
- tasks[0].timestamp = sunCalcResult.dusk_time;
- }
- else if (timePointName == "luxOn") {
- tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000;
- }
- else if (timePointName == "luxOff") {
- tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000;
- }
- else if (timePointName == "profileTimepoint") {
- tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
- }
-
- let info = "aplikovany bod profilu";
- let onOrOff = "";
- value == 1 ? onOrOff = "on" : onOrOff = "off";
-
- turnLine(onOrOff, params.line, info);
-
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- if (!SETTINGS.masterNodeIsResponding) {
- //ak neodpoveda, nebudeme vykonavat ziadne commands, okrem cmd-terminal cmd-master
- errorHandler.sendMessageToService("Master node is not responding");
-
- let stop = true;
-
- if (type === "cmd-terminal" || type === "cmd-master") stop = false;
- if (stop) {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
- }
-
- let contactorStatus = 1;
- if (relaysData[line] != undefined) contactorStatus = relaysData[line].contactor;
-
- if (line === 0 || contactorStatus === 0 || FLOW.deviceStatus.state_of_breaker[line] === "Off") {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- // TODO: -> status offline for rvo if rotary_switch_state is OFF, this is source of errors
- //check if rotary_switch_state == "Off"
- // state_of_braker: disconnected = true?
-
- if (!rsPort.isOpen) {
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- //RE-CALCULATE VALUES
- //set actual time for broadcast
- if (register == 87 && params.recipient === 2) {
- var d = new Date();
- params.byte1 = d.getHours();//h
- params.byte2 = d.getMinutes();//m
- }
-
- //SET DUSK/DAWN FOR BROADCAST
- //Time of dusk
- if (register == 6 && params.recipient === 2) {
-
- if (type != "cmd-terminal") {
- let sunCalcResult = calculateDuskDawn();
- params.byte1 = sunCalcResult["dusk_hours"];//h
- params.byte2 = sunCalcResult["dusk_minutes"];//m
- }
- }
-
- //Time of dawn
- if (register == 7 && params.recipient === 2) {
- if (type != "cmd-terminal") {
- let sunCalcResult = calculateDuskDawn();
- params.byte1 = sunCalcResult["dawn_hours"];//h
- params.byte2 = sunCalcResult["dawn_minutes"];//m
- }
- }
- //-----------------------
-
- instance.send(SEND_TO.debug, "address: " + node + " register:" + register + "type: " + type);
-
- var startTime, endTime;
- startTime = new Date();
-
- let saveToTb = true;
- if (!tbname) saveToTb = false;
-
- let resp = com_generic(node, params.recipient, params.rw, register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
- let readBytes = 11;
- let timeout = 4000;
-
-
- // await keyword is important, otherwise incorrect data is returned!
- await writeData(rsPort, resp, readBytes, timeout).then(function(data) {
-
- //sometimes happens, that status of node changes even if line was turned off and should be offline. To prevent this, we return if line contactor is 0:
- if (itIsNodeCommand && line && relaysData[line].contactor !== 1) return;
-
- endTime = new Date();
- var timeDiff = endTime - startTime;
-
- //data je array z 11 bytov: 1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data a 2 byty CRC
- let dataBytes = data.slice(5, 9);
- let result = detectIfResponseIsValid(data);
-
- if(register === 79) console.log("node responsee: ", dataBytes);
- //ak sa odpoved zacina 0 - je to v poriadku, inak je NOK
- let message = result.message; // OK, NOK
- let message_type = result.type;
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- console.log("detected response:", result);
- logger.debug("Cmd-mngr: writeData done " + message_type + " duration: " + timeDiff + " type: " + params.debug, params, result);
- }
- }
-
- let values = {};
-
- //CMD FINISHED
- if (message == "OK") {
-
- updateNodeStatus(node, true);
-
- //write
- if (type == "set_node_profile") {
- let result = cmdCounterResolve(node);
- if (result == 0) {
- dbNodes.modify({ processed: true }).where("node", node).callback(function(err, response) {
-
- sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
-
- logger.debug("--> profil úspešne odoslaný na node č. " + node);
- nodesData[node].processed = true;
- nodeProfileSendFail.delete(node);
- });
- }
- }
-
- //parse read response
- if (params.rw == 0) {
- values = processResponse(register, dataBytes); //read
- console.log("command params: ", params.address, register);
- }
-
- if (itIsNodeCommand) {
- values.comm_status = "OK";
- values.status = "OK";
- nodesData[node].readout = { ...nodesData[node].readout, ...values };
- }
-
- //master node
- if (node == 0) {
- sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status");
- SETTINGS.masterNodeIsResponding = true;
- if (register == 4) values["edge_fw_version"] = SETTINGS.edge_fw_version;
- }
-
- if (params.debug) {
- //logger.debug("saveToTb", saveToTb, tbname, values);
- }
-
- if (saveToTb && type != "node-regular-read") {
- sendTelemetry(values, tbname);
- }
- else {
- if (type == "cmd-terminal") {
- terminalCommandResponse(params, "SUCCESS", data);
- }
- }
-
- }
- else {
-
- terminalCommandResponse(params, "ERROR", data);
- handleNokResponseOnRsPort("handleNOK else block", params, itIsNodeCommand, saveToTb);
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- //logger.debug("writeData err: ", error, result, params);
- logger.debug("writeData err: ", tbname, node, register, values);
- }
- }
-
- //logger.debug(error, result, params);
- }
- }).catch(function(reason) {
-
- //console.log("writeData catch exception", reason);
- instance.send(SEND_TO.debug, reason);
-
- terminalCommandResponse(params, "FAILURE", null, reason);
- handleNokResponseOnRsPort("handleNOK catch block", params, itIsNodeCommand, saveToTb);
-
- if (params.hasOwnProperty("debug")) {
- if (params.debug) {
- logger.debug("-->WRITE FAILED: " + reason, params.debug, params);
- }
- }
-
- });
-
- }
- else {
- if (currentTask.debug) {
- // currentTask.timestamp <= currentTimestamp && logger.debug("currentTask is not processed - task is in the future", currentTask);
- }
-
- interval = setInterval(runTasks, LONG_INTERVAL);
- return;
- }
-
- //console.log("----->runTasks - setInterval", new Date());
- interval = setInterval(runTasks, SHORT_INTERVAL);
- }
-
-
- function handleNokResponseOnRsPort(message, params, itIsNodeCommand, saveToTb) {
-
- let node = params.address;
- let register = params.register;
- let type = params.type;
- let tbName = params.tbname;
- if (!tbName) return;
-
- let values = {};
-
- let updateStatus = updateNodeStatus(node, false);
-
- if (itIsNodeCommand) {
- values.comm_status = "NOK";
- nodesData[node].readout.comm_status = "NOK";
- }
-
- if (updateStatus) {
- values.status = "NOK";
- nodesData[node].readout.status = "NOK";
- }
-
- if (type === "node-regular-read") return;
-
- //master node
- if (node == 0) {
- sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
- logger.debug("master_node_is_not_responding", params);
- SETTINGS.masterNodeIsResponding = false;
-
- if (register == 4) values["master_node_version"] = "NOK";
- }
-
- if (type == "set_node_profile") {
- delete cmdCounter[node];
- logger.debug("profil nebol úspešne odoslaný na node č. ", params);
-
- if (!nodeProfileSendFail.has(node)) {
- sendNotification("CMD Manager: process cmd", tbName, "configuration_of_dimming_profile_to_node_failed", { node: node }, "", SEND_TO.tb, instance);
- nodeProfileSendFail.add(node);
- }
- }
-
- // console.log("------",node, register, type, itIsNodeCommand, updateStatus, saveToTb, values);
- if (saveToTb) {
- sendTelemetry(values, tbName);
- }
-
- }
-
- function sendNodesData() {
- Object.keys(nodesData).forEach(node => {
- if (nodesData[node]["status"] !== "OFFLINE") {
- sendTelemetry(nodesData[node].readout, nodesData[node].tbname);
- nodesData[node].readout = {};
- }
- })
- }
-
-
- /**
- * function handles requests from terminal
- * responseType can be "SUCCESS", "ERROR" or "FAILURE", depending on rsPort data.
- * FAILURE means, that we got into catch block of writeData function.
- */
- function terminalCommandResponse(params, responseType, data = null, reason = "") { //success, error, failure
-
- if (params.refFlowdataKey === undefined) {
- //console.log("params.refFlowdataKey is undefined", params);
- return;
- }
- else {
- console.log("params.refFlowdataKey: ", params);
- }
-
- let message = null;
- let type = null;
-
- switch (responseType) {
- case "SUCCESS":
- message = "cmd-terminal SUCCESS";
- type = "SUCCESS";
- break;
- case "ERROR":
- message = "cmd-terminal FAILED";
- type = "ERROR";
- break;
- case "FAILURE":
- message = "ERROR WRITE FAILED: " + reason;
- type = "ERROR";
- break;
- default:
- type = undefined;
- }
-
- logger.debug(message);
- logger.debug(params);
-
- //make http response
- let responseObj = {}
- responseObj["type"] = type;
-
- if (responseType == "FAILURE") responseObj["message"] = "ERROR WRITE FAILED: " + reason;
- else responseObj["bytes"] = data;
-
- let refFlowdata = refFlowdataObj[params.refFlowdataKey]; //holds reference to httprequest flowdata
- if (refFlowdata) {
- refFlowdata.data = responseObj;
- instance.send(SEND_TO.http_response, refFlowdata);
- }
- }
-
-
- /**
- * function handles tasks, that are not needed to run through masterNode. To make them run smooth without waiting for other tasks to be completed, we moved them in separate function
- */
- function reportEdgeDateTimeAndNumberOfLuminaires() {
-
- //Number of ok and nok nodes on platform does not equals to total number of nodes.
- //possible error is, that nodesData object is changing all the time. To make a proper calculation of ok,nok luminaires, we make a copy of it:
- let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
-
- const ts = Date.now();
- const keys = Object.keys(nodesData_clone);
-
- const number_of_luminaires = keys.length;
- let number_of_ok_luminaires = 0;
- let number_of_nok_luminaires = 0;
-
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
- let nodeObj = nodesData_clone[key];
- if (nodeObj.tbname == undefined) continue;
-
- if (nodeObj.status === "OFFLINE") {
- nodeObj.node_status_before_offline === true ? number_of_ok_luminaires++ : number_of_nok_luminaires++;
- }
- else if (nodeObj.status == true) number_of_ok_luminaires++;
- else number_of_nok_luminaires++;
-
- }
-
- const values = {
- "number_of_luminaires": number_of_luminaires,
- "number_of_ok_luminaires": number_of_ok_luminaires,
- "number_of_nok_luminaires": number_of_nok_luminaires,
- "edge_date_time": ts - ts % 60000 //round to full minute
- };
-
- sendTelemetry(values, SETTINGS.rvoTbName, ts);
- }
-
-
- function handleRsPort() {
-
- console.log("cmd_man: handleRsPort called");
- //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
- // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
- // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
-
- if (SETTINGS.serial_port == "" || SETTINGS.serial_port == undefined || SETTINGS.serial_port.length === 1) SETTINGS.serial_port = "ttymxc4";
- console.log('SETTINGS.serial_port', SETTINGS.serial_port);
- //rsPort = new SerialPort({path: `/dev/${SETTINGS.serial_port}`, baudRate: 57600, autoOpen: false });
- rsPort = new SerialPort({ path: "/dev/ttyUSB0", baudRate: 9600, autoOpen: false });
- //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
- //rsPort.setMaxListeners(0);
-
- rsPort.on('open', async function() {
-
- logger.debug("CMD manager - rsPort opened success");
- console.log("CMD manager - rsPort opened success");
-
- await runSyncExec(`stty -F /dev/${SETTINGS.serial_port} 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke`).then(function(status) {
- instance.send(SEND_TO.debug, "RPC runSyncExec - Promise Resolved:" + status);
-
- logger.debug(0, "RPC runSyncExec - Promise Resolved:" + status);
-
- }).catch(function(reason) {
- instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason);
- console.log("cmd_man: rsport error", reason);
- });
- });
-
- rsPort.on('error', function(err) {
-
- //TODO report to service!!!
- //errLogger.error(exports.title, "unable to open port", SETTINGS.serial_port, err.message);
- errorHandler.sendMessageToService([exports.title, "unable to open port", SETTINGS.serial_port, err.message], 0);
- console.log("cmd_manager: unable to open rsport", SETTINGS.serial_port, err.message);
- instance.send(SEND_TO.debug, err.message);
- });
-
- rsPort.on("close", () => {
- setTimeout(() => rsPort.open(), 1000);
- });
-
-
- rsPort.open(function(err) {
- if (err) console.log('rsport open error', err);
- })
- }
-
-
- instance.on("close", () => {
- clearInterval(interval);
- clearInterval(customTasksInterval);
- clearInterval(setCorrectTime);
- clearInterval(sendNodeReadout);
- clearInterval(accelerometerInterval);
- rsPort.close();
- });
-
- instance.on("0", _ => {
- main();
- })
-
- instance.on("1", async function(flowdata) {
-
- //instance.send(SEND_TO.debug, "on Data");
- //instance.send(SEND_TO.debug, flowdata);
-
- //logger.debug(flowdata.data);
-
- //just testing functions
- if (flowdata.data == "open") {
- if (!rsPort.isOpen) rsPort.open();
- 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(SEND_TO.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, 5000);
- }
- else if (cmd == "reload_relays") {
- loadRelaysData(flowdata.data.line);
-
- if (flowdata.data.dataChanged) {
- if (!flowdata.data.value) {
- reportOfflineNodeStatus(flowdata.data.line);
- }
- else {
- reportOnlineNodeStatus(flowdata.data.line);
- }
- }
-
- }
- else if (cmd == "rotary_switch_state") {
- let value = flowdata.data.value;
-
- //state was changed
- if (rotary_switch_state != value) {
- if (value == "Off") {
- //vyreportovat vsetky svietdla
- reportOfflineNodeStatus();
- }
-
- rotary_switch_state = value;
- }
- }
- else if (cmd == "lux_sensor") {
- lux_sensor = parseInt(flowdata.data.value);
-
- // POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ??
- if (lux_sensor < 100) {
-
- // we send lux_sensor value to all nodes:
- let params = getParams(PRIORITY_TYPES.node_broadcast);
-
- params.recipient = 2;//2 broadcast, address = 0
- params.address = 0xffffffff;//Broadcast
-
- let ba = longToByteArray(lux_sensor);
-
- params.byte3 = ba[1];//msb
- params.byte4 = ba[0];
- params.timestamp = PRIORITY_TYPES.node_broadcast;
- params.info = "run broadcast: Actual Lux level from cabinet";
- params.register = 95;//Actual Lux level from cabinet
- params.rw = 1;//write
-
- tasks.push(params);
-
- //process profiles
- turnOnOffLinesAccordingToLuxSensor(lux_sensor);
- }
- }
- else if (cmd == "state_of_breaker") {
- //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";
- if (value == "Off") 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 }, "", SEND_TO.tb, instance, "circuit_breaker");
- else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
-
- //report status liniu
- sendTelemetry({ status: status }, tbname)
-
- //current value
- if (value == "Off") reportOfflineNodeStatus(line); //vyreportovat vsetky svietidla na linii
- }
-
- }
- }
- else {
- logger.debug("undefined cmd", cmd);
- }
- }
- }
-
- return;
- }
-
- //data from worksys
- if (flowdata.data.hasOwnProperty("topic")) {
-
- let data = getNested(flowdata.data, "content", "data");
-
- //if we get temperature in senica from senica-prod01
- let temperature = getNested(flowdata.data, "content", "senica_temperature");
-
- if (temperature !== undefined) {
- temperatureInSenica = temperature;
- return;
- }
-
- if (data === undefined) {
- console.log("Invalid rpc command came from platform");
- return;
- }
-
- let command = data.params.command;
- let method = data.method;
- let profile = data.params.payload;
- if (profile == undefined) profile = "";
- let entity = data.params.entities[0];
- let entity_type = entity.entity_type;
- let tbname = entity.tb_name;
-
- instance.send(SEND_TO.debug, flowdata.data);
- logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
- logger.debug("----------------------------");
-
- if (entity_type == "street_luminaire" || entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4") {
- 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) {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- value = parseInt(value);
- if (value > 0) value = value + 128;
-
- params.type = "node-onetime-write";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;
- params.recipient = 1;
- params.byte4 = value;
- params.rw = 1;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'set dimming from platform';
- //params.debug = true;
-
- //debug(params);
- logger.debug("dimming", params);
-
- tasks.push(params);
-
- setTimeout(function() {
-
- //spustime o 4 sekundy neskor, s prioritou PRIORITY_TYPES.high_priority
- //a pridame aj vyreportovanie dimmingu
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 1;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read dimming (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - vykon
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 76;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Power (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - prud svietidla
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 75;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read Input Current (after set dimming from platform)';
- //params.debug = true;
-
- tasks.push(params);
- }
-
- //pridame aj vyreportovanie - power faktor - ucinnik
- {
- let params = getParams(PRIORITY_TYPES.high_priority);
-
- params.type = "node-onetime-read";
- params.tbname = tbname;
- params.address = node;
- params.register = 77;
- params.recipient = 1;
- params.rw = 0;
- params.timestamp = PRIORITY_TYPES.high_priority;
- params.info = 'read power factor (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(SEND_TO.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(SEND_TO.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) {
-
- if (profile != "") profile = JSON.stringify(profile);
- dbNodes.modify({ processed: false, profile: profile }).where("node", node).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, "dimming_profile_was_processed_for_node", { node: node }, profile, SEND_TO.tb, instance);
-
- nodesData[node].processed = false;
- nodesData[node].profile = profile;
-
- processNodeProfile(node);
- });
- }
- }
- }
- else {
-
- instance.send(SEND_TO.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).callback(function(err, response) {
-
- //update profile
- logger.debug("worksys - update relay profile done:", profile);
- instance.send(SEND_TO.debug, "worksys - update relay profile done");
-
- relaysData[line].profile = profile;
-
- loadRelaysData(line)
- logger.debug("loadRelaysData DONE for line", line);
-
- buildTasks({ processLineProfiles: true, line: line });
-
- sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", { line: line }, profile, SEND_TO.tb, instance);
- });
- break;
- }
- }
- }
- else if (method == "set_command") {
- let value = data.params.payload.value;
-
- if (command === "switch") {
-
- // if we receive rpc from platform, to switch maintenance mode, we set SETTINGS.maintenance_mode flow variable to value;
- if (entity_type === "edb" || entity_type === "edb_ver4_se") SETTINGS.maintenance_mode = value;
-
- const relayObject = getObjectByTbValue(relaysData, tbname);
- let line = 0;
- if (isObject(relayObject)) line = relayObject.line;
-
- // v relaysData je contactor bud 0 alebo 1, ale z platformy prichadza true, false;
- if (value == false) turnLine("off", line, "command received from platform");
- else turnLine("on", line, "command received from platform");
- }
- }
- else {
- instance.send(SEND_TO.debug, "undefined method " + method);
- logger.debug("undefined method", method);
- }
-
- return;
- }
- else {
- instance.send(SEND_TO.debug, "UNKNOW entity_type " + entity_type);
- logger.debug("UNKNOW entity_type", entity_type);
- }
- return;
- }
-
- //terminal
- if (!rsPort.isOpen) await rsPort.open();
-
- let params = flowdata.data.body;
- if (params == undefined) {
- //logger.debug("CMD manager flowdata.data.body is undefined");
- return;
- }
-
- params.priority = PRIORITY_TYPES.terminal;
- params.type = "cmd-terminal";
- params.tbname = "";
- params.timestamp = PRIORITY_TYPES.terminal;
- params.addMinutesToTimestamp = 0;// do not repeat task!!!
- params.debug = true;
-
- let timestamp = Date.now();
- params.refFlowdataKey = timestamp;
- //params.refFlowdata = flowdata;
- //refFlowdata = flowdata;
-
- //console.log("flowdata", flowdata);
-
- cleanUpRefFlowdataObj();
-
- refFlowdataObj[timestamp] = flowdata;
-
- //fix
- //params.address = params.adress;
- logger.debug("received from terminal", params);
- logger.debug("date/time:", new Date());
- logger.debug("tasks length:", tasks.length);
-
- //tasks = [];
-
- //add to tasks
- tasks.push(params);
-
- }
- }
- })
-
-
- //function gets value of a nested property in an object and returns undefined if it does not exists:
- function getNested(obj, ...args) {
- return args.reduce((obj, level) => obj && obj[level], obj)
- }
-
-
- /**
- * setCorrectTime function runs once per hour
- * If it is 3 o'clock, it sets actual time, which is got from services
- * https://service-prod01.worksys.io/gettime
- * If also detects Read Only Filesystem once a day
- */
- function setCorrectPlcTimeOnceADay() {
-
- const currentTime = new Date();
- if (currentTime.getHours() != 3) return;
-
- RESTBuilder.make(function(builder) {
-
- if (!builder) return;
-
- builder.method('GET');
- builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
-
- builder.callback(function(err, response, output) {
-
- if (err) {
- console.log(err);
- return;
- }
-
- const res = output.response;
-
- try {
-
- const obj = JSON.parse(res);
- let d = new Date(obj.date);
-
- const now = new Date();
-
- let diffInMinutes = now.getTimezoneOffset();
- console.log("---->TimezoneOffset", diffInMinutes);
-
- if (d instanceof Date) {
-
- // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
-
- let year = d.getFullYear();
- let month = addZeroBefore(d.getMonth() + 1);
- let day = addZeroBefore(d.getDate());
-
- let hours = addZeroBefore(d.getHours());
- let minutes = addZeroBefore(d.getMinutes());
- let seconds = addZeroBefore(d.getSeconds());
-
- let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-
- exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
- console.log(dateStr);
-
- monitor.info("failed timedatectl set-time", err, stderr);
- }
- else {
- monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
- }
-
- });
- }
-
- } catch (error) {
- logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
- monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
- }
-
- // we detect readOnlyFileSystem once an hour as well
- detectReadOnlyFilesystem();
-
- });
- });
-
- }
-
-
- function detectReadOnlyFilesystem() {
- exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
- if (err || stderr) {
- console.error(err);
- console.log(stderr);
-
- } else {
- //console.log("Read-only", stdout);
-
- let lines = stdout + "";
- lines = lines.split("\n");
-
- let readOnlyDetected = "";
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("/dev/mmcblk0p2")) {
- readOnlyDetected = lines[i];
- }
- }
-
- if (readOnlyDetected !== "") {
- errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
- monitor.info("Read only filesystem detected");
- }
-
- }
- });
- }
-
-
-
-
-
-
-
-
- ///helper functions
- function sendTelemetry(values, tbname, date = Date.now()) {
- const dataToTb = {
- [tbname]: [
- {
- "ts": date,
- "values": values
- }
- ]
- }
-
- tbHandler.sendToTb(dataToTb, instance);
- }
-
- function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) {
-
- if (date === undefined) date = new Date();
- //if(duskOffset === undefined) duskOffset = 0;
- //if(dawnOffset === undefined) dawnOffset = 0;
-
- //let line = keys[i];
- let profilestr = "";
- if (relaysData[line] != undefined) profilestr = relaysData[line].profile;
-
- let result = {};
-
- var times = SunCalc.getTimes(date, latitude, longitude);
- let dawn = new Date(times.sunrise);//usvit
- let dusk = new Date(times.sunset);//sumrak
-
-
- //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
- //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
-
-
- let dusk_astro_clock_offset = duskOffset;//minutes
- let dawn_astro_clock_offset = dawnOffset;//minutes
-
- try {
-
- let profile = JSON.parse(profilestr);
- if (Object.keys(profile).length === 0) throw ("profile is not defined");
-
- //Jednoduchý režim
- if (profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false) {
-
- }
-
- //Režim astrohodín
- if (profile.astro_clock == true) {
- //if(profile.dusk_lux_sensor == false)
- {
- if (profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt(profile.dusk_astro_clock_offset);
- }
-
- //if(profile.dawn_lux_sensor == false)
- {
- if (profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt(profile.dawn_astro_clock_offset);
- }
-
- }
-
- //dusk - súmrak
- //down, sunrise - svitanie
-
- } catch (error) {
- if (profilestr != "") {
- logger.debug(profilestr);
- logger.debug(error);
- }
- }
-
- result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
-
- dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset * 60000);
- dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset * 60000);
-
- result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
- result.dusk_hours = dusk.getHours();
- result.dusk_minutes = dusk.getMinutes();
-
- result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
- result.dawn_hours = dawn.getHours();
- result.dawn_minutes = dawn.getMinutes();
-
- result.dusk_time = dusk.getTime();
- result.dawn_time = dawn.getTime();
-
- result.dusk_astro_clock_offset = dusk_astro_clock_offset;
- result.dawn_astro_clock_offset = dawn_astro_clock_offset;
-
- return result;
- }
-
-
- function processResponse(register, bytes) {
-
- let values = {};
-
- let byte3 = bytes[0];
- let byte2 = bytes[1];
- let byte1 = bytes[2];
- let byte0 = bytes[3];
-
- //status
- if (register == 0) {
- let statecode = bytesToInt(bytes);
- values = { "statecode": statecode };
- return values;
- }
-
- //Dimming, CCT
- else 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;
- }
-
- //
- else if (register == 4) {
- values["master_node_version"] = bytes[1] + "." + bytes[2];
- //logger.debug("FW Version", register, bytes);
- }
-
- //Napätie
- else if (register == 74) {
- let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
- values["voltage"] = Number(voltage);
- }
-
- //Prúd
- else if (register == 75) {
- let current = bytesToInt(bytes);
- values["current"] = current;
- }
-
- //výkon
- else if (register == 76) {
- let power = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["power"] = Number(power);
- }
-
- //účinník
- else if (register == 77) {
- let power_factor = Math.cos(bytesToInt(bytes) * 0.1 * (Math.PI / 180)).toFixed(2);
- values["power_factor"] = Number(power_factor);
- }
-
- //frekvencia
- else if (register == 78) {
- let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
- values["frequency"] = Number(frequency);
- }
-
- //energia
- else if (register == 79) {
- let energy = bytesToInt(bytes);
- console.log("bytesToIng ",bytesToInt(bytes))
- //Energiu treba reportovať v kWh -> delit 1000
- values["energy"] = energy / 1000;
- }
-
- //doba života
- else if (register == 80) {
- let lifetime = (bytesToInt(bytes) / 60).toFixed(2);
- values["lifetime"] = Number(lifetime);
- }
-
- //nastavenie profilu
- else if (register == 8) {
- let time_schedule_settings = bytesToInt(bytes);
- values["time_schedule_settings"] = time_schedule_settings;
- }
-
- //naklon - nateraz sa z nodu nevycitava! kvoli problemom s accelerometrom a vracanymi hodnotami, posielame temp a x y z vo funkcii accelerometerData()
- else if (register == 84) {
- values["temperature"] = byte3 >= 128 ? (byte3 - 128) * (-1) : byte3;
- values["inclination_x"] = byte2 >= 128 ? (byte2 - 128) * (-1) : byte2;
- values["inclination_y"] = byte1 >= 128 ? (byte1 - 128) * (-1) : byte1;
- values["inclination_z"] = byte0 >= 128 ? (byte0 - 128) * (-1) : byte0;
- }
-
- //FW verzia nodu
- else if (register == 89) {
- //formát: "Byte3: Byte2.Byte1 (Byte0)"
- values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
- }
-
- else if (register == 87 || register == 6 || register == 7) {
- var d = new Date();
- d.setHours(byte3, byte2, 0, 0);
- let timestamp = d.getTime();
-
- //aktuálny čas
- if (register == 87) values["actual_time"] = timestamp;
- //čas súmraku
- else if (register == 6) values["dusk_time"] = timestamp;
- //čas úsvitu
- else if (register == 7) values["dawn_time"] = timestamp;
- }
-
- return values;
- }
-
-
- //byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
- function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
- let resp = [];
-
- let cmd = register;
-
- if (typeof adresa === 'string') adresa = parseInt(adresa);
- if (typeof byte1 === 'string') byte1 = parseInt(byte1);
- if (typeof byte2 === 'string') byte2 = parseInt(byte2);
- if (typeof byte3 === 'string') byte3 = parseInt(byte3);
- if (typeof byte4 === 'string') byte4 = parseInt(byte4);
-
- if (rw === 0) {
- cmd = cmd + 0x8000;
- }
-
- //master
- if (rec === 0) adresa = 0;
-
- if (rec === 2) {
- adresa = 0xffffffff;//Broadcast
- }
-
- //recipient
- if (rec === 3) {
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(0xFF);
- resp.push(adresa & 0xFF);//band
- }
- else {
- resp.push((adresa >> 24) & 0xFF);//rshift
- resp.push((adresa >> 16) & 0xFF);
- resp.push((adresa >> 8) & 0xFF);
- resp.push(adresa & 0xFF);
-
- if (rec === 2) {
- resp.push(0xFF);
- }
- else resp.push(0);
- }
-
- resp.push((cmd >> 8) & 0xFF);//rshift
- resp.push(cmd & 0xFF);//band
- resp.push(byte1 & 0xFF);//band
- resp.push(byte2 & 0xFF);//band
- resp.push(byte3 & 0xFF);//band
- resp.push(byte4 & 0xFF);//band
-
- //let data = '12345';
- let crc = crc16('ARC', resp);
- let c1 = (crc >> 8) & 0xFF;
- let c2 = crc & 0xFF;
-
- resp.push(c1);
- resp.push(c2);
-
- //logger.debug("checksum", crc);
- //logger.debug("resp", resp);
-
- return resp;
-
- }
-
- function getObjectByTbValue(object, tbname) {
- return object[Object.keys(object).find(key => object[key].tbname === tbname)];
- }
-
- function isObject(item) {
- return (typeof item === "object" && !Array.isArray(item) && item !== null);
- }
-
-
- // we fake data, that should be received from accelerometer, as they are a bit unreliable. (temperature, x,y,z)
- function accelerometerData() {
-
- if (temperatureInSenica === null) return;
-
- //clone nodesData and relaysData objects
- let nodesData_clone = JSON.parse(JSON.stringify(nodesData));
- let relaysData_clone = JSON.parse(JSON.stringify(relaysData));
-
- for (const key in relaysData_clone) {
-
- const lineData = relaysData_clone[key];
- const lineNumber = lineData.line;
- const contactor = lineData.contactor;
-
- if (lineNumber === 0) continue;
-
- if (contactor === 1) {
-
- let date = Date.now();
-
- Object.keys(nodesData_clone).forEach((node, index) => {
-
- setTimeout(function() {
-
- if (nodesData_clone[node].line === lineNumber) {
-
- // NOTE: if status of luminaire is NOK or OFFLINE, we do not send data;
- let status = nodesData_clone[node].status;
- if (status === "OFFLINE" || !status) return;
-
- let x = null;
- if (naklony.hasOwnProperty(node)) x = naklony[node].naklon;
- if (x === null) x = 0;
-
- sendTelemetry({ temperature: Math.round(temperatureInSenica + 10 + Math.floor(Math.random() * 3)), inclination_x: x, inclination_y: 0, inclination_z: 0 }, nodesData_clone[node].tbname, date);
- }
-
- }, (index + 1) * 500);
- })
-
- }
- }
- }
-
+ tasks.push(params);
+ }
+
+ //kazdu hodinu skontrolovat nastavenie profilov
+ {
+ let params = getParams(PRIORITY_TYPES.fw_detection);
+ params.type = "process_profiles";
+
+ let timestampStart = PRIORITY_TYPES.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(PRIORITY_TYPES.node_cmd);
+ params.type = "edge_date_time";
+
+ let timestampStart = PRIORITY_TYPES.node_cmd;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = 1;
+ params.tbname = FLOW.OMS_edgeName;
+ params.info = "reportovanie aktuálneho času na LM - EDGE-Date Time";
+ //logger.debug("BUILD Master node FW verzia");
+ tasks.push(params);
+ }
+
+ {
+ //edge_date_time
+
+ let params = getParams(PRIORITY_TYPES.node_cmd);
+ params.type = "number_of_luminaires";
+
+ let timestampStart = PRIORITY_TYPES.node_cmd + 1;
+ params.timestamp = timestampStart;
+ params.addMinutesToTimestamp = 1;
+ params.tbname = FLOW.OMS_edgeName;
+ params.info = "reportovanie number_of_luminaires";
+
+ tasks.push(params);
+ }
+
+ monitor.info("tasks created:", tasks.length);
+ }
+
+
+ /**
+ * We process line profile, where "astro_clock": true
+ * example profile:
+ *
+ "dawn_lux_sensor": true,
+ "dusk_lux_sensor": true,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 0,
+ "dusk_astro_clock_offset": 10,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+
+ * if dawn: if currentTimestamp is in timewindow "dawnTime + and - dawn_lux_sensor_time_window" and lux value >= lux_sensor_value, we switch off the line.
+ * if dusk: we do oposite
+ *
+ * dawn: usvit - lux je nad hranicou - vypnem
+ * dusk: sumrak - lux je pod hranicou - zapnem
+ */
+ function turnOnOffLinesAccordingToLuxSensor(lux_sensor_value)
+ {
+
+ let 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;
+ const contactor = relaysData[line].contactor;
+
+ try {
+
+ let profile = JSON.parse(profilestr);
+ if(Object.keys(profile).length === 0) throw ("turnOnOffLinesAccordingToLuxSensor - profile is not defined");
+
+ if(profile.astro_clock == true)
+ {
+ let sunCalcResult = calculateDuskDawn(now, line);
+
+ //usvit
+ if(profile.dawn_lux_sensor == true)
+ {
+ let lux_sensor_time_window1 = sunCalcResult.dawn_time - (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60); // LUX_SENSOR_TIME_WINDOW x 1000 x 60 --> dostaneme odpocet/pripocitanie minut
+ let lux_sensor_time_window2 = sunCalcResult.dawn_time + (parseInt( profile.dawn_lux_sensor_time_window ) * 1000 * 60);
+
+ if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
+ {
+ if(lux_sensor_value > profile.dawn_lux_sensor_value)
+ {
+ if(contactor) turnOffLine(line, "Profile: dawn - turnOff line according to lux sensor");
+ }
+ }
+ }
+
+ //sumrak
+ if(profile.dusk_lux_sensor == true)
+ {
+ let lux_sensor_time_window1 = sunCalcResult.dusk_time - (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60);
+ let lux_sensor_time_window2 = sunCalcResult.dusk_time + (parseInt( profile.dusk_lux_sensor_time_window ) * 1000 * 60);
+
+ if(currentTimestamp >= lux_sensor_time_window1 && currentTimestamp <= lux_sensor_time_window2)
+ {
+ if(lux_sensor_value < profile.dusk_lux_sensor_value)
+ {
+ if(!contactor) turnOnLine(line, "Profile: dusk - turnOn line according to lux sensor");
+ }
+ }
+ }
+
+ }
+
+ } catch (error) {
+ if(profilestr !== "" ) monitor.info('Error parsing profile in turnOnOffLinesAccordingToLuxSensor', error);
+ }
+
+ }
+
+ }
+
+
+ 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"]}, "", SEND_TO.tb, instance);
+ reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
+ }
+ }
+
+ var nextDay = new Date();
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ sunCalcResult = calculateDuskDawn(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"]}, "", SEND_TO.tb, instance);
+ reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
+ }
+ }
+
+ var nextDay = new Date();
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ sunCalcResult = calculateDuskDawn(nextDay);
+ reportDuskDawn.dawn_time = sunCalcResult.dawn_time;
+
+ }
+ //--------------------------------------------------------
+
+ //sort tasks based on timestamp
+ tasks.sort(function (a, b) {
+ if(a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp)
+ {
+ return a.priority - b.priority;
+ }
+ return a.timestamp - b.timestamp;
+ });
+
+ if(tasks.length == 0 )
+ {
+ instance.send(SEND_TO.debug, "no tasks created");
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ if(!rsPort.isOpen)
+ {
+ instance.send(SEND_TO.debug, "!rsPort.isOpen");
+ //await rsPort.open();
+ }
+
+ let currentTask = tasks[0];
+
+ if(currentTask.debug)
+ {
+ //logger.debug("--->task to process", currentTask);
+ }
+
+ if(currentTask.timestamp <= currentTimestamp)
+ {
+ let params = {...tasks[0]};
+
+ //allow terminal commands
+ if(FLOW.OMS_maintenance_mode && params.type !== "cmd-terminal")
+ {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ let type = params.type;
+ let tbname = params.tbname;
+ let nodeKey = params.address;
+
+ let 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 || params.timePointName) repeatTask = true;
+
+ if(repeatTask)
+ {
+ if(type === "cmd")
+ {
+ //set next start time automatically
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+ }
+ }
+ else
+ {
+ tasks.shift();
+ }
+
+ //custom tasks
+ if(type == "number_of_luminaires")
+ {
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+
+ //treba reportovat node status
+ {
+ //number_of_luminaires
+ //number_of_ok_luminaires
+ //number_of_nok_luminaires
+
+ let keys = Object.keys(nodesData);
+
+ let number_of_luminaires = keys.length;
+ let number_of_ok_luminaires = 0;
+ let number_of_nok_luminaires = 0;
+
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+ let nodeObj = nodesData[key];
+ if(nodeObj.tbname == undefined) continue;
+
+ if(nodeObj.status) number_of_ok_luminaires++;
+ else number_of_nok_luminaires++;
+ }
+
+ let values = {
+ number_of_luminaires: number_of_luminaires,
+ number_of_ok_luminaires: number_of_ok_luminaires,
+ number_of_nok_luminaires: number_of_nok_luminaires
+ };
+
+ let dataToTb = {
+ [FLOW.OMS_edgeName]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+
+ return;
+ }
+ }
+
+
+ //kontrola nespracovanych profilov nodov
+ if(type == "process_profiles")
+ {
+ 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, SHORT_INTERVAL);
+ return;
+ }
+
+ if(type == "edge_date_time")
+ {
+ const ts = Date.now();
+
+ let values = {"edge_date_time": ts};
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": ts,
+ "values": values
+ }
+ ]
+ }
+
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+
+ instance.send(SEND_TO.tb, dataToTb);
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ return;
+ }
+
+ //relay
+ if(type == "relay")
+ {
+
+ const timePointName = params.timePointName;
+ const value = params.value;
+
+ let date = new Date();
+ date.setDate(date.getDate() + 1);//next day
+
+ let sunCalcResult;
+ sunCalcResult = calculateDuskDawn(date, params.line);
+
+ if(timePointName == "dawn")
+ {
+ tasks[0].timestamp = sunCalcResult.dawn_time;
+ }
+ else if(timePointName == "dusk")
+ {
+ tasks[0].timestamp = sunCalcResult.dusk_time;
+ }
+ else if(timePointName == "luxOn")
+ {
+ tasks[0].timestamp = sunCalcResult.dusk_time + params.dusk_lux_sensor_time_window * 60000;
+ }
+ else if(timePointName == "luxOff")
+ {
+ tasks[0].timestamp = sunCalcResult.dawn_time + params.dawn_lux_sensor_time_window * 60000;
+ }
+ else if(timePointName == "profileTimepoint")
+ {
+ tasks[0].timestamp = currentTimestamp + tasks[0].addMinutesToTimestamp * 60000;
+ }
+
+ let info = "aplikovany bod profilu";
+ let message = "";
+ if(value == 1)
+ {
+ turnOnLine(params.line, info);
+ message = "on";
+ }
+ else if(value == 0)
+ {
+ turnOffLine(params.line, info);
+ message = "off";
+ }
+
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.INFO, "aplikovaný bod profilu línie " + params.line + " - stav: " + message, "", SEND_TO.tb, instance, null );
+ sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "switching_profile_point_applied_to_line", {line: params.line, value: message}, "", SEND_TO.tb, instance );
+
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ 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 dido_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(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+ }
+
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+
+ 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, LONG_INTERVAL);
+ 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(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ return;
+ }
+
+ if(!rsPort.isOpen)
+ {
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ 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/DAWN FOR BROADCAST
+ //Time of dusk
+ if(params.register == 6 && params.recipient === 2)
+ {
+
+ if(params.type != "cmd-terminal")
+ {
+ let sunCalcResult = calculateDuskDawn();
+ let dusk_hours = sunCalcResult["dusk_hours"];
+ let dusk_minutes = sunCalcResult["dusk_minutes"];
+
+ params.byte1 = dusk_hours;//h
+ params.byte2 = dusk_minutes;//m
+ params.byte3 = 0;//s
+ 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, "", SEND_TO.tb, instance, null );
+ }
+ }
+
+ //Time of dawn
+ if(params.register == 7 && params.recipient === 2)
+ {
+ if(params.type != "cmd-terminal")
+ {
+ let sunCalcResult = calculateDuskDawn();
+ let dawn_hours = sunCalcResult["dawn_hours"];
+ let dawn_minutes = sunCalcResult["dawn_minutes"];
+
+ params.byte1 = dawn_hours;//h
+ params.byte2 = dawn_minutes;//m
+ params.byte3 = 0;//s
+ 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, "", SEND_TO.tb, instance, null );
+ }
+
+ }
+ //-----------------------
+
+
+ let register = params.register;
+ instance.send(SEND_TO.debug, "address: " + params.address + " register:" + params.register + "type: " + params.type);
+
+ var startTime, endTime;
+ startTime = new Date();
+
+ let resp = com_generic(params.address, params.recipient, params.rw, params.register, params.name, params.byte1, params.byte2, params.byte3, params.byte4);
+ let readBytes = 11;
+ let timeout = 5000;
+
+ await writeData(rsPort, resp, readBytes, timeout).then(function (data) {
+
+ endTime = new Date();
+ var timeDiff = endTime - startTime;
+
+ //--1-4 adresa, 5 status ak je status 0 - ok, nasleduju 4 byty data
+ //let bytes = data.slice(0);
+ let bytes = data;
+ let dataBytes = data.slice(5,9);
+
+ let result = detectIfResponseIsValid(bytes);
+
+ let message = result.message;
+ let type = result.type;
+ let error = result.error;
+
+ //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}, "", SEND_TO.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", "", SEND_TO.tb, instance, "rvo_status" );
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" );
+ sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_responding_again", {}, "", SEND_TO.tb, instance, "rvo_status" );
+ FLOW.OMS_masterNodeIsResponding = true;
+ }
+
+ //odoslanie príkazu z terminálu - dáta
+ if(params.type == "cmd-terminal")
+ {
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.DEBUG, "odoslanie príkazu z terminálu", params, SEND_TO.tb, instance, null );
+ sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "command_was_sent_from_terminal_interface", {}, params, SEND_TO.tb, instance );
+ }
+
+ if(params.debug)
+ {
+ logger.debug("saveToTb", saveToTb, tbname, values);
+ }
+
+ if(saveToTb)
+ {
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+
+ }
+ else
+ {
+
+ if(params.type == "cmd-terminal")
+ {
+ if(params.refFlowdataKey != undefined)
+ {
+
+ logger.debug("cmd-terminal SUCCESS");
+ logger.debug(currentTask);
+
+ //make http response
+ let responseObj = {};
+ responseObj["type"] = "SUCESS";
+ responseObj["bytes"] = data;
+
+ //params.refFlowdata.data = responseObj;
+ //instance.send(SEND_TO.http_response, params.refFlowdata);
+
+ let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
+ refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, refFlowdata);
+
+ }
+ else
+ {
+ console.log("params.refFlowdataKey is undefined", params);
+ }
+ }
+
+ }
+
+ }
+ else
+ {
+
+ 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(SEND_TO.http_response, params.refFlowdata);
+
+ let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
+ if(refFlowdata !== undefined)
+ {
+ refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, refFlowdata);
+ }
+
+
+ }
+
+ /*
+ if(params.type == "cmd-terminal")
+ {
+ if(params.refFlowdata != undefined)
+ {
+
+ logger.debug("cmd-terminal FAILED");
+ logger.debug(currentTask);
+
+ //make http response
+ let responseObj = {};
+ responseObj["type"] = "ERROR";
+ responseObj["bytes"] = data;
+
+ params.refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, params.refFlowdata);
+
+ }
+ }
+ */
+
+ if(params.address == 0)
+ {
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status");
+ sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
+ logger.debug("master_node_is_not_responding", params);
+ FLOW.OMS_masterNodeIsResponding = false;
+ }
+
+ if(params.type == "set_node_profile")
+ {
+ delete cmdCounter[params.address];
+ let tbname = nodesData[ params.address ].tbname;
+
+ logger.debug( "profil nebol úspešne odoslaný na node č. ", params, result, resp);
+
+ //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "profil nebol úspešne odoslaný na node č. " + params.address, "", SEND_TO.tb, instance, null );
+ sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance );
+ }
+
+ //is it node?
+ if(nodesData.hasOwnProperty(params.address))
+ {
+ if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
+ }
+
+ //Master node version
+ //if(params.register == 4 && saveToTb)
+ if(saveToTb)
+ {
+ let values = {
+ "status": "NOK"
+ };
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+ }
+
+ //instance.send(SEND_TO.debug, result);
+
+ if(params.hasOwnProperty("debug"))
+ {
+ if(params.debug)
+ {
+ logger.debug("writeData err: ", error, result, params);
+ }
+ }
+
+ //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(SEND_TO.http_response, params.refFlowdata);
+
+ let refFlowdata = refFlowdataObj[ params.refFlowdataKey ];
+ if(refFlowdata !== undefined)
+ {
+ refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, refFlowdata);
+ }
+
+
+ }
+ /*
+ if(params.type == "cmd-terminal")
+ {
+ if(params.refFlowdata != undefined)
+ {
+
+ logger.debug("cmd-terminal FAILED");
+ logger.debug(currentTask);
+
+ //make http response
+ let responseObj = {};
+ responseObj["type"] = "ERROR WRITE FAILED: " + reason;
+ //responseObj["bytes"] = data;
+
+ params.refFlowdata.data = responseObj;
+ instance.send(SEND_TO.http_response, params.refFlowdata);
+
+ //refFlowdata = undefined;
+ }
+ }
+ */
+
+ if(params.hasOwnProperty("debug"))
+ {
+ if(params.debug)
+ {
+ logger.debug("-->WRITE FAILED: " + reason, params.debug, params);
+ }
+ }
+
+ upateNodeStatus(params.address, false);
+
+ let tbname = params.tbname;
+
+ let saveToTb = true;
+ if(tbname == null || tbname == undefined || tbname == "") saveToTb = false;
+
+ if(params.address == 0)
+ {
+ //sendNotification("CMD Manager: process cmd", relaysData[0].tbname, ERRWEIGHT.ALERT, "Master node not responding", "", SEND_TO.tb, instance, "rvo_status");
+ sendNotification("CMD Manager: process cmd", FLOW.OMS_edgeName, "master_node_is_not_responding", {}, "", SEND_TO.tb, instance, "rvo_status");
+ logger.debug("master_node_is_not_responding", params);
+
+ FLOW.OMS_masterNodeIsResponding = false;
+ }
+
+ if(params.type == "set_node_profile")
+ {
+ delete cmdCounter[params.address];
+ let tbname = nodesData[ params.address ].tbname;
+
+ logger.debug( "profil nebol úspešne odoslaný na node č. ", params, resp);
+
+ //sendNotification("CMD Manager: process cmd", tbname, ERRWEIGHT.ALERT, "odosielanie profilu na node č. " + params.address + " zlyhalo", "", SEND_TO.tb, instance, null );
+ sendNotification("CMD Manager: process cmd", tbname, "configuration_of_dimming_profile_to_node_failed", {node: params.address}, "", SEND_TO.tb, instance );
+ }
+
+ //is it node?
+ if(nodesData.hasOwnProperty(params.address))
+ {
+ if(cmdNOKNodeCounter[params.address] < 5) saveToTb = false;
+ }
+
+ //Master node version
+ if(params.register == 4 && saveToTb)
+ {
+ let values = {
+ "status": "NOK",
+ "master_node_version": "NOK"
+ };
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+
+ FLOW.OMS_masterNodeIsResponding = false;
+ }
+ //treba?
+ /*
+ else if(saveToTb)
+ {
+ let values = {
+ "comm_status": "no_comm"
+ };
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ instance.send(SEND_TO.tb, dataToTb);
+ }
+ */
+
+ instance.send(SEND_TO.debug, reason);
+ });
+
+ }
+ else
+ {
+ if(currentTask.debug)
+ {
+ //currentTask.timestamp <= currentTimestamp
+ logger.debug("currentTask is not processed - task is in the future", currentTask);
+ }
+
+ interval = setInterval(runTasks, LONG_INTERVAL);
+ return;
+ }
+
+ //console.log("----->runTasks - setInterval", new Date());
+ interval = setInterval(runTasks, SHORT_INTERVAL);
+ }
+
+
+ //! rsPort LM = "/dev/ttymxc4", rsPort UNIPI = "/dev/ttyUSB0"
+ // const rsPort = new SerialPort("/dev/ttymxc4", { autoOpen: false }); //LM
+ // const rsPort = new SerialPort("/dev/ttyUSB0", { autoOpen: false }); // UNIPI
+
+ if(FLOW.OMS_serial_port == "" || FLOW.OMS_serial_port == undefined || FLOW.OMS_serial_port.length === 1) FLOW.OMS_serial_port = "ttymxc4";
+ const rsPort = new SerialPort(`/dev/${FLOW.OMS_serial_port}`, { autoOpen: false });
+ //(node:16372) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 13 data listeners added to [SerialPort]. Use emitter.setMaxListeners() to increase limit
+ //rsPort.setMaxListeners(0);
+
+ rsPort.on('open', async function() {
+
+ logger.debug("CMD manager - rsPort opened sucess");
+
+ 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(SEND_TO.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(SEND_TO.infoSender, dataToInfoSender);
+
+ logger.debug(0, "---------------------------->START message send to service", dataToInfoSender);
+
+ }).catch(function (reason) {
+ instance.send(SEND_TO.debug, "CMD manager - RPC runSyncExec - promise rejected:" + reason);
+ });
+ });
+
+ rsPort.on('error', function(err) {
+
+ //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(SEND_TO.debug, err.message);
+ });
+
+ rsPort.on("close", () => {
+ rsPort.close();
+ });
+
+ //loadRelaysData();
+ rsPort.open();
+
+ instance.on("close", () => {
+ clearInterval(interval);
+ rsPort.close();
+ });
+
+
+ instance.on("data", async function(flowdata) {
+
+ //instance.send(SEND_TO.debug, "on Data");
+ //instance.send(SEND_TO.debug, flowdata);
+
+ //logger.debug(flowdata.data);
+
+ //just testing functions
+ if(flowdata.data == "open")
+ {
+ if(!rsPort.isOpen) rsPort.open();
+ 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(SEND_TO.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, LONG_INTERVAL);
+ }
+ else if(cmd == "reload_relays")
+ {
+ loadRelaysData(flowdata.data.line);
+
+ if(flowdata.data.dataChanged)
+ {
+ if(!flowdata.data.value)
+ {
+ reportOfflineNodeStatus(flowdata.data.line);
+ }
+ else
+ {
+ reportOnlineNodeStatus(flowdata.data.line);
+ }
+ }
+
+ }
+ 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);
+
+ // POSSIBLE SOURCE OF PROBLEMS, IF USER SETS LUX TRESHOLD LEVEL GREATER THAN 100 - WE SHOULD BE CHECKING "DUSK/DAWN_LUX_SENSOR_VALUE" IN PROFILE MAYBE ??
+ if(lux_sensor < 100)
+ {
+
+ // we send lux_sensor value to all nodes:
+ let params = getParams(PRIORITY_TYPES.node_broadcast);
+
+ params.recipient = 2;//2 broadcast, address = 0
+ params.address = 0xffffffff;//Broadcast
+
+ let ba = longToByteArray(lux_sensor);
+
+ params.byte3 = ba[1];//msb
+ params.byte4 = ba[0];
+ params.timestamp = PRIORITY_TYPES.node_broadcast;
+ params.info = "run broadcast: Actual Lux level from cabinet";
+ params.register = 95;//Actual Lux level from cabinet
+ params.rw = 1;//write
+
+ tasks.push(params);
+
+
+ //process profiles
+ turnOnOffLinesAccordingToLuxSensor(lux_sensor);
+ }
+ }
+ else if(cmd == "state_of_breaker")
+ {
+ //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}, "", SEND_TO.tb, instance, "circuit_breaker");
+ else sendNotification("CMD Manager: onData", tbname, "circuit_breaker_was_turned_on_line", {line: line}, "", SEND_TO.tb, instance, "circuit_breaker");
+
+ //report status liniu
+ let values = {
+ "status": status
+ };
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //instance.send(SEND_TO.tb, dataToTb);
+ tbHandler.sendToTb(dataToTb, instance);
+
+ //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(SEND_TO.debug, flowdata.data);
+ logger.debug("--->worksys", flowdata.data, data.params, entity, entity_type, command, method);
+ logger.debug("----------------------------");
+
+ if(entity_type == "street_luminaire"|| entity_type === "street_luminaire_v4_1" || entity_type === "street_luminaire_v4_1cez" || entity_type === "street_luminaire_v4")
+ {
+ 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(PRIORITY_TYPES.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 = PRIORITY_TYPES.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 PRIORITY_TYPES.high_priority
+ //a pridame aj vyreportovanie dimmingu
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 1;//dimming
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read dimming (after set dimming from platform)';
+ params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - vykon
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 76;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Power (after set dimming from platform)';
+ params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - prud svietidla
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 75;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read Input Current (after set dimming from platform)';
+ params.debug = true;
+
+ tasks.push(params);
+ }
+
+ //pridame aj vyreportovanie - power faktor - ucinnik
+ {
+ let params = getParams(PRIORITY_TYPES.high_priority);
+
+ params.type = "cmd";
+ params.tbname = tbname;
+ params.address = node;
+ params.register = 77;
+ params.recipient = 1;//slave
+ params.rw = 0;//read
+ params.timestamp = PRIORITY_TYPES.high_priority;
+ params.info = 'read power factor - Cos phi (after set dimming from platform)';
+ params.debug = true;
+
+ tasks.push(params);
+ }
+
+ },4000);
+
+
+ nodeWasFound = true;
+
+ break;
+ }
+ }
+
+ if(!nodeWasFound)
+ {
+ logger.debug("set dimming from platform", "unable to find tbname", tbname);
+ }
+ }
+ else
+ {
+ instance.send(SEND_TO.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(SEND_TO.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, SEND_TO.tb, instance, null );
+ sendNotification("CMD manager", tbname, "dimming_profile_was_processed_for_node", {node: node}, profile, SEND_TO.tb, instance );
+
+ nodesData[node].processed = false;
+ nodesData[node].profile = profile;
+
+ let line = nodesData[node].line;
+ processNodeProfile(node);
+
+ });
+ });
+ }
+ }
+ }
+ else
+ {
+
+ instance.send(SEND_TO.debug, "unknown method " + method);
+ logger.debug("unknown method", method);
+
+ return;
+ }
+ }
+
+ //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(SEND_TO.debug, "worksys - update relay profile done");
+
+ loadRelaysData(line).then(function (data) {
+ logger.debug("loadRelaysData DONE for line", line);
+ buildTasks({processLineProfiles: true, line: line});
+ });
+
+ sendNotification("CMD manager - set profile from worksys", tbname, "switching_profile_was_processed_for_line", {line: line}, profile, SEND_TO.tb, instance );
+
+ });
+ });
+ break;
+ }
+ }
+ }
+ else if(method == "set_command")
+ {
+ let value = data.params.payload.value;
+
+ if(command === "switch")
+ {
+
+ // if we receive rpc from platform, to switch maintenance mode, we set OMS_maintenance_mode flow variable to value;
+ if(entity_type === "edb" || entity_type === "edb_ver4_se") FLOW.variables.OMS_maintenance_mode = value;
+
+ let responseRelays = await promisifyBuilder(dbRelays.find().where("tbname", tbname));
+
+ let line = 0;
+ if(responseRelays.length == 1) line = responseRelays[0].line;
+
+ if(value == false) turnOffLine(line, "command received form platform");
+ else turnOnLine(line, "command received form platform");
+ }
+ }
+ else
+ {
+ instance.send(SEND_TO.debug, "undefined method " + method);
+ logger.debug("undefined method", method);
+ }
+
+ return;
+ }
+ else
+ {
+ instance.send(SEND_TO.debug, "UNKNOW entity_type " + entity_type);
+ logger.debug("UNKNOW entity_type", entity_type);
+ }
+ return;
+ }
+
+ //terminal
+ if(!rsPort.isOpen) await rsPort.open();
+
+ let params = flowdata.data.body;
+ if(params == undefined)
+ {
+ //logger.debug("CMD manager flowdata.data.body is undefined");
+ return;
+ }
+
+ params.priority = PRIORITY_TYPES.terminal;
+ params.type = "cmd-terminal";
+ params.tbname = "";
+ params.timestamp = PRIORITY_TYPES.terminal;
+ params.addMinutesToTimestamp = 0;// do not repeat task!!!
+ params.debug = true;
+
+ let timestamp = Date.now();
+ params.refFlowdataKey = timestamp;
+ //params.refFlowdata = flowdata;
+ //refFlowdata = flowdata;
+
+ //console.log("flowdata", flowdata);
+
+ cleanUpRefFlowdataObj();
+
+ refFlowdataObj[ timestamp ] = flowdata;
+
+ //fix
+ //params.address = params.adress;
+ logger.debug("received from terminal", params);
+ logger.debug("date/time:", new Date());
+ logger.debug("tasks length:", tasks.length);
+
+ //tasks = [];
+
+ //add to tasks
+ tasks.push(params);
+
+ }
+ }
+ })
} // end of instance.export
+
+/**
+ * setCorrectTime function runs once per hour
+ * If it is 3 o'clock, it sets actual time, which is got from services
+ * https://service-prod01.worksys.io/gettime
+ * If also detects Read Only Filesystem once a day
+ */
+function setCorrectPlcTimeOnceADay()
+{
+
+ const currentTime = new Date();
+ if(currentTime.getHours() != 3) return;
+
+ RESTBuilder.make(function(builder) {
+
+ if(!builder) return;
+
+ builder.method('GET');
+ builder.url('http://192.168.252.2:8004/gettime?projects_id=1');
+
+ builder.callback(function(err, response, output) {
+
+ if (err) {
+ console.log(err);
+ return;
+ }
+
+ const res = output.response;
+
+ try {
+
+ const obj = JSON.parse(res);
+ let d = new Date(obj.date);
+
+ const now = new Date();
+
+ let diffInMinutes = now.getTimezoneOffset();
+ console.log("---->TimezoneOffset", diffInMinutes);
+
+ if(d instanceof Date)
+ {
+
+ // monitor.info("----------->setCorrectPlcTimeOnceADay() current js date:", d, d.getHours());
+
+ let year = d.getFullYear();
+ let month = addZeroBefore(d.getMonth() + 1);
+ let day = addZeroBefore(d.getDate());
+
+ let hours = addZeroBefore(d.getHours());
+ let minutes = addZeroBefore(d.getMinutes() );
+ let seconds = addZeroBefore(d.getSeconds());
+
+ let dateStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+
+ exec(`sudo timedatectl set-time "${dateStr}"`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+ console.log(dateStr);
+
+ monitor.info("failed timedatectl set-time", err, stderr);
+ }
+ else
+ {
+ monitor.info("setCorrectPlcTimeOnceADay() --> Nastaveny cas na: ", dateStr);
+ }
+
+ });
+ }
+
+ } catch (error) {
+ logger.debug("setCorrectPlcTimeOnceADay - function error", error, res);
+ monitor.info("setCorrectPlcTimeOnceADay - function error", error, res);
+ }
+
+ // we detect readOnlyFileSystem once an hour as well
+ detectReadOnlyFilesystem();
+
+ });
+ });
+
+}
+
+
+function detectReadOnlyFilesystem()
+{
+ exec(`sudo egrep " ro,|,ro " /proc/mounts`, (err, stdout, stderr) => {
+ if (err || stderr) {
+ console.error(err);
+ console.log(stderr);
+
+ } else {
+ //console.log("Read-only", stdout);
+
+ let lines = stdout + "";
+ lines = lines.split("\n");
+
+ let readOnlyDetected = "";
+ for(let i = 0; i < lines.length; i++)
+ {
+ if(lines[i].startsWith("/dev/mmcblk0p2"))
+ {
+ readOnlyDetected = lines[i];
+ }
+ }
+
+ if(readOnlyDetected !== "")
+ {
+ errorHandler.sendMessageToService("Detected: Read-only file system: " + readOnlyDetected);
+ monitor.info("Read only filesystem detected");
+ }
+
+ }
+ });
+}
+
+let setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
+setCorrectPlcTimeOnceADay();
+
+
+
+
+
+
+
+
+
+///helper functions
+
+function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0)
+{
+
+ if(date === undefined) date = new Date();
+ //if(duskOffset === undefined) duskOffset = 0;
+ //if(dawnOffset === undefined) dawnOffset = 0;
+
+ //let line = keys[i];
+ let profilestr = "";
+ if(relaysData[line] != undefined) profilestr = relaysData[line].profile;
+
+ let result = {};
+
+ var times = SunCalc.getTimes(date, latitude, longitude);
+ let dawn = new Date(times.sunrise);//usvit
+ let dusk = new Date(times.sunset);//sumrak
+
+
+ //http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
+ //https://mapa.zoznam.sk/zisti-gps-suradnice-m6
+
+
+ let dusk_astro_clock_offset = duskOffset;//minutes
+ let dawn_astro_clock_offset = dawnOffset;//minutes
+
+ try {
+
+ let profile = JSON.parse(profilestr);
+ if(Object.keys(profile).length === 0) throw ("profile is not defined");
+
+ //Jednoduchý režim
+ if(profile.astro_clock == false && profile.dusk_lux_sensor == false && profile.dawn_lux_sensor == false)
+ {
+
+ }
+
+ //Režim astrohodín
+ if(profile.astro_clock == true)
+ {
+ //if(profile.dusk_lux_sensor == false)
+ {
+ if(profile.hasOwnProperty("dusk_astro_clock_offset")) dusk_astro_clock_offset = parseInt( profile.dusk_astro_clock_offset );
+ }
+
+ //if(profile.dawn_lux_sensor == false)
+ {
+ if(profile.hasOwnProperty("dawn_astro_clock_offset")) dawn_astro_clock_offset = parseInt( profile.dawn_astro_clock_offset );
+ }
+
+ }
+
+ //dusk - súmrak
+ //down, sunrise - svitanie
+
+ } catch (error) {
+ if(profilestr != "")
+ {
+ logger.debug(profilestr);
+ logger.debug(error);
+ }
+ }
+
+ result.dusk_no_offset = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dawn_no_offset = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
+
+ dusk = new Date(dusk.getTime() + gmtOffset + dusk_astro_clock_offset*60000);
+ dawn = new Date(dawn.getTime() + gmtOffset + dawn_astro_clock_offset*60000);
+
+ result.dusk = addZeroBefore(dusk.getHours()) + ":" + addZeroBefore(dusk.getMinutes());
+ result.dusk_hours = dusk.getHours();
+ result.dusk_minutes = dusk.getMinutes();
+
+ result.dawn = addZeroBefore(dawn.getHours()) + ":" + addZeroBefore(dawn.getMinutes());
+ result.dawn_hours = dawn.getHours();
+ result.dawn_minutes = dawn.getMinutes();
+
+ result.dusk_time = dusk.getTime();
+ result.dawn_time = dawn.getTime();
+
+ result.dusk_astro_clock_offset = dusk_astro_clock_offset;
+ result.dawn_astro_clock_offset = dawn_astro_clock_offset;
+
+ return result;
+}
+
+
+function processResponse(register, bytes)
+{
+
+ let values = {};
+
+ let byte3 = bytes[0];
+ let byte2 = bytes[1];
+ let byte1 = bytes[2];
+ let byte0 = bytes[3];
+
+ //status
+ if(register == 0)
+ {
+ let statecode = bytesToInt(bytes);
+ values = {"statecode": statecode};
+ return values;
+ }
+
+ //Dimming, CCT
+ if(register == 1)
+ {
+ let brightness = 0;
+ let dimming = byte0;
+ if(dimming > 128) {
+ //dimming = -128;
+ brightness = dimming - 128;
+ }
+
+ //cct
+ //Ak Byte3 == 1: CCT = (Byte2*256)+Byte1
+ let cct;
+ if(byte3 == 1) cct = byte2*256 + byte1;
+ else cct = bytesToInt(bytes.slice(0, 3));
+
+ //cct podla auditu
+
+ values["dimming"] = brightness;
+ return values;
+ }
+
+ //
+ if(register == 4)
+ {
+ values["master_node_version"] = bytes[1] + "." + bytes[2];
+ //logger.debug("FW Version", register, bytes);
+ }
+
+ //Napätie
+ if(register == 74)
+ {
+ let voltage = (bytesToInt(bytes) * 0.1).toFixed(1);
+ values["voltage"] = Number(voltage);
+ }
+
+ //Prúd
+ if(register == 75)
+ {
+ let current = bytesToInt(bytes);
+ values["current"] = current;
+ }
+
+ //výkon
+ if(register == 76)
+ {
+ let power = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["power"] = Number(power);
+ }
+
+ //účinník
+ if(register == 77)
+ {
+ let power_factor = Math.cos(bytesToInt(bytes) * 0.1).toFixed(2);
+ values["power_factor"] = Number(power_factor);
+ }
+
+ //frekvencia
+ if(register == 78)
+ {
+ let frequency = (bytesToInt(bytes) * 0.1).toFixed(2);
+ values["frequency"] = Number(frequency);
+ }
+
+ //energia
+ if(register == 79)
+ {
+ let energy = bytesToInt(bytes);
+
+ //Energiu treba reportovať v kWh. Teda číslo, ktoré príde treba podeliť 1000. Toto som ti možno zle napísal.
+
+ values["energy"] = energy / 1000;
+ }
+
+ //doba života
+ if(register == 80)
+ {
+ let lifetime = ( bytesToInt(bytes) / 60).toFixed(2);
+ values["lifetime"] = Number(lifetime);
+ }
+
+ //nastavenie profilu
+ if(register == 8)
+ {
+ let time_schedule_settings = bytesToInt(bytes);
+ values["time_schedule_settings"] = time_schedule_settings;
+ }
+
+ //skupinová adresa 1
+ if(register == 3)
+ {
+ let gr_add_1 = bytesToInt(byte0);
+ values["gr_add_1"] = gr_add_1;
+
+ let gr_add_2 = bytesToInt(byte1);
+ values["gr_add_2"] = gr_add_2;
+
+ let gr_add_3 = bytesToInt(byte2);
+ values["gr_add_3"] = gr_add_3;
+
+ let gr_add_4 = bytesToInt(byte3);
+ values["gr_add_4"] = gr_add_4;
+ }
+
+ //naklon
+ if(register == 84)
+ {
+ let temp;
+ if(byte3 >= 128)
+ {
+ temp = (byte3 - 128) * (-1);
+ }
+ else
+ {
+ temp = byte3;
+ }
+
+ let inclination_x;
+ if(byte2 >= 128)
+ {
+ inclination_x = (byte2 - 128) * (-1);
+ }
+ else
+ {
+ inclination_x = byte2;
+ }
+
+ let inclination_y;
+ if(byte1 >= 128)
+ {
+ inclination_y = (byte1 - 128) * (-1);
+ }
+ else
+ {
+ inclination_y = byte1;
+ }
+
+ let inclination_z;
+ if(byte0 >= 128)
+ {
+ inclination_z = (byte0 - 128) * (-1);
+ }
+ else
+ {
+ inclination_z = byte0;
+ }
+
+ values["temperature"] = temp;
+
+ //náklon x
+ values["inclination_x"] = inclination_x;
+
+ //náklon y
+ values["inclination_y"] = inclination_y;
+
+ //náklon z
+ values["inclination_z"] = inclination_z;
+ }
+
+ let h = byte3;
+ let m = byte2;
+ let s = byte1;
+
+ let timestamp;
+
+ if(register == 87 || register == 6 || register == 7 )
+ {
+ //if(byte3 < 10) h = "0" + byte3;
+ //if(byte2 < 10) m = "0" + byte2;
+ //if(byte1 < 10) s = "0" + byte1;
+
+ var d = new Date();
+ d.setHours(h);
+ d.setMinutes(m);
+ d.setSeconds(s);
+
+ timestamp = d.getTime();
+ }
+
+ //aktuálny čas
+ if(register == 87)
+ {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["actual_time"] = h + ":" + m + ":" + s;
+
+ values["actual_time"] = timestamp;
+ }
+
+ //čas súmraku
+ if(register == 6)
+ {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["dusk_time"] = h + ":" + m + ":" + s;
+
+ values["dusk_time"] = timestamp;
+ }
+
+ //čas úsvitu
+ if(register == 7)
+ {
+ //Byte3 - hodiny, Byte 2 - minúty, Byte 1 -sek.
+ //values["dawn_time"] = h + ":" + m + ":" + s;
+
+ values["dawn_time"] = timestamp;
+ }
+
+ //FW verzia
+ if(register == 89)
+ {
+ //formát: "Byte3: Byte2.Byte1 (Byte0)"
+ values["fw_version"] = byte3 + ":" + byte2 + "." + byte1 + "(" + byte0 + ")";
+ }
+
+ return values;
+}
+
+
+//byte1 MSB = data3, byte2 = data2, byte3 = data1, byte4 = data0 LSB
+function com_generic(adresa, rec, rw, register, name, byte1, byte2, byte3, byte4) {
+ let resp = [];
+
+ let cmd = register;
+
+ if (typeof adresa === 'string') adresa = parseInt(adresa);
+ if (typeof byte1 === 'string') byte1 = parseInt(byte1);
+ if (typeof byte2 === 'string') byte2 = parseInt(byte2);
+ if (typeof byte3 === 'string') byte3 = parseInt(byte3);
+ if (typeof byte4 === 'string') byte4 = parseInt(byte4);
+
+ if (rw === 0)
+ {
+ cmd = cmd + 0x8000;
+ }
+
+ //master
+ if(rec === 0) adresa = 0;
+
+ if(rec === 2)
+ {
+ adresa = 0xffffffff;//Broadcast
+ }
+
+ //recipient
+ if (rec === 3)
+ {
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push(0xFF);
+ resp.push( adresa & 0xFF );//band
+ }
+ else
+ {
+ resp.push( (adresa >> 24) & 0xFF);//rshift
+ resp.push( (adresa >> 16) & 0xFF);
+ resp.push( (adresa >> 8) & 0xFF);
+ resp.push( adresa & 0xFF );
+
+ if (rec === 2)
+ {
+ resp.push(0xFF);
+ }
+ else resp.push(0);
+ }
+
+ resp.push( (cmd >> 8) & 0xFF);//rshift
+ resp.push( cmd & 0xFF );//band
+ resp.push( byte1 & 0xFF );//band
+ resp.push( byte2 & 0xFF );//band
+ resp.push( byte3 & 0xFF );//band
+ resp.push( byte4 & 0xFF );//band
+
+ //let data = '12345';
+ let crc = crc16('ARC', resp);
+ let c1 = (crc >> 8) & 0xFF;
+ let c2 = crc & 0xFF;
+
+ resp.push(c1);
+ resp.push(c2);
+
+ //logger.debug("checksum", crc);
+ //logger.debug("resp", resp);
+
+ return resp;
+
+}
+
+
+
+
+
+
+// SAMPLE DATA
+
+const relaysDataExample =
+{
+ '0': {
+ line: 0,
+ tbname: 'jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV',
+ contactor: 1,
+ profile: ''
+ },
+ '1': {
+ line: 1,
+ tbname: 'MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O',
+ contactor: 1,
+ profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+ },
+ '2': {
+ line: 2,
+ tbname: 'jBL12pg63eX4N9P7zy0lJLyEJKmlbkGwZMx0avQV',
+ contactor: 1,
+ profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+ },
+ '3': {
+ line: 3,
+ tbname: 'aAOzENGrvpbe0VoK7D6E1a819PZmdg3nl24JLQMk',
+ contactor: 1,
+ profile: '{"intervals":[{"value":1,"end_time":"13:00","start_time":"13:00"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
+ }
+}
+
+
+const rpcSwitchOffLine =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 8,
+ "method": "set_command",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "edb_line",
+ "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
+ }
+ ],
+ "command": "switch",
+ "payload": {
+ "value": false
+ }
+ }
+ }
+ }
+}
+
+const rpcSetNodeDimming =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 10,
+ "method": "set_command",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "street_luminaire",
+ "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
+ }
+ ],
+ "command": "dimming",
+ "payload": {
+ "value": 5
+ }
+ }
+ }
+ }
+}
+
+const rpcLineProfile =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 9,
+ "method": "set_profile",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "edb_line",
+ "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
+ }
+ ],
+ "payload": {
+ "intervals": [
+ {
+ "value": 0,
+ "end_time": "20:00",
+ "start_time": "13:00"
+ },
+ {
+ "value": 1,
+ "end_time": "05:30",
+ "start_time": "20:00"
+ },
+ {
+ "value": 0,
+ "end_time": "13:00",
+ "start_time": "05:30"
+ }
+ ],
+ "astro_clock": true,
+ "dawn_lux_sensor": false,
+ "dusk_lux_sensor": false,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 0,
+ "dusk_astro_clock_offset": 0,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+ }
+ }
+ }
+ }
+}
+
+
+const rpcNodeProfile =
+{
+ "topic": "v1/gateway/rpc",
+ "content": {
+ "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
+ "data": {
+ "id": 11,
+ "method": "set_profile",
+ "params": {
+ "entities": [
+ {
+ "entity_type": "street_luminaire",
+ "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
+ }
+ ],
+ "payload": {
+ "intervals": [
+ {
+ "cct": 3000,
+ "value": 0,
+ "end_time": "17:50",
+ "start_time": "13:00"
+ },
+ {
+ "cct": 3000,
+ "value": 100,
+ "end_time": "21:30",
+ "start_time": "17:50"
+ },
+ {
+ "cct": 3000,
+ "value": 0,
+ "end_time": "13:00",
+ "start_time": "07:10"
+ },
+ {
+ "cct": 3000,
+ "value": 50,
+ "end_time": "00:00",
+ "start_time": "21:30"
+ },
+ {
+ "cct": 3000,
+ "value": 10,
+ "end_time": "04:30",
+ "start_time": "00:00"
+ },
+ {
+ "cct": 3000,
+ "value": 100,
+ "end_time": "07:10",
+ "start_time": "04:30"
+ }
+ ],
+ "astro_clock": true,
+ "dawn_lux_sensor": false,
+ "dusk_lux_sensor": false,
+ "dawn_lux_sensor_value": 5,
+ "dusk_lux_sensor_value": 5,
+ "dawn_astro_clock_offset": 30,
+ "dusk_astro_clock_offset": 20,
+ "dawn_lux_sensor_time_window": 30,
+ "dusk_lux_sensor_time_window": 30,
+ "dawn_astro_clock_time_window": 60,
+ "dusk_astro_clock_time_window": 60
+ }
+ }
+ }
+ }
+}
+
+ const sunCalcExample = {
+ dusk_no_offset: '20:18',
+ dawn_no_offset: '05:19',
+ dusk: '20:18',
+ dusk_hours: 20,
+ dusk_minutes: 18,
+ dawn: '05:19',
+ dawn_hours: 5,
+ dawn_minutes: 19,
+ dusk_time: 1715278688962,
+ dawn_time: 1715224744357,
+ dusk_astro_clock_offset: 0,
+ dawn_astro_clock_offset: 0
+}
diff --git a/flow/count.js b/flow/count.js
deleted file mode 100644
index fa92ee9..0000000
--- a/flow/count.js
+++ /dev/null
@@ -1,60 +0,0 @@
-exports.id = 'count';
-exports.title = 'Count';
-exports.version = '1.0.1';
-exports.author = 'John Graves';
-exports.color = '#656D78';
-exports.icon = 'plus-square';
-exports.input = 2;
-exports.output = 1;
-exports.options = { increment: 1, initialvalue: 1 };
-exports.readme = `# Counter
-
-Counter Number of times called.`;
-
-exports.html = ``;
-
-exports.readme = `# Count
-
-This component counts the number of messages received.
-
-__Response:__
-
-Integer value based on the initial value and increment settings.
-
-__Arguments:__
-- Initial Value: What number should be output on the receipt of the first message.
-- Increment: What should the increment be for each following message received.`;
-
-exports.install = function(instance) {
-
- var count = 0;
- var initialCall = true;
-
- instance.on('data', function(flowdata) {
- var index = flowdata.index;
- if (index) {
- instance.debug('Reset Count.');
- count = instance.options.initialvalue;
- initialCall = true;
- } else {
- // If this is the first time, set the value to 'initial value'
- if(initialCall) {
- initialCall = false;
- count = instance.options.initialvalue;
- } else
- count = count+instance.options.increment;
- instance.status('Count:' + count);
- instance.send2(count);
- }
- });
-
- instance.on('options', function() {
- count = instance.options.initialvalue;
- initialCall = true;
- });
-
-};
diff --git a/flow/csv_import.js b/flow/csv_import.js
new file mode 100644
index 0000000..5ae1e68
--- /dev/null
+++ b/flow/csv_import.js
@@ -0,0 +1,175 @@
+exports.id = 'csv_import';
+exports.title = 'CsvImport';
+exports.version = '1.0.0';
+exports.group = 'Worksys';
+exports.color = '#2134B0';
+exports.input = 1;
+exports.output = ["red", "white"];
+exports.click = false;
+exports.author = 'Daniel Segeš';
+exports.icon = 'file-import';
+exports.options = { edge: "undefined" };
+
+exports.html = ``;
+
+exports.readme = `# load csv to table db`;
+
+//config
+let delimiter = ";";
+let uniqueColumn = "node";
+let path = "flow/audit_test_panel.csv";
+let startFrom = 1;
+let table = "nodes";
+let mapImport = {
+ 2: "node",
+ 4: "tbname",
+ 3: "line"
+};
+
+//10.0.0.62
+delimiter = ";";
+uniqueColumn = "node";
+path = "flow/audit_rvo14_lampy.csv";
+startFrom = 1;
+table = "nodes";
+mapImport = {
+ 1: "node",
+ 3: "tbname",
+ 2: "line"
+};
+
+//notification
+delimiter = ";";
+uniqueColumn = undefined;
+path = "flow/notifikacie.csv";
+startFrom = 1;
+table = "notifications";
+mapImport = {
+ 0: "key",
+ 1: "weight",
+ 2: "en",
+ 3: "sk"
+};
+
+const fs = require('fs');
+
+exports.install = function(instance) {
+
+ //console.log("csv import installed");
+
+ instance.on("close", () => {
+
+ })
+
+
+ instance.on("data", (flowdata) => {
+
+ instance.send(0, "start import");
+ console.log("csv import", flowdata.data);
+
+ //{table: "nodes", startFrom: 1, delimiter: ";", uniqueColumn: "node", path: "flow/audit_rvo14_lampy.csv", mapImport: {1: "node", 3: "tbname", 2: "line"}}
+
+
+ if(typeof flowdata.data === 'object')
+ {
+ console.log("*******************", flowdata.data);
+
+ if(!flowdata.data.hasOwnProperty("table"))
+ {
+ instance.send(0, "!!!!csv import - nedefinovana tabulka");
+ return;
+ }
+
+ if(!flowdata.data.hasOwnProperty("uniqueColumn"))
+ {
+ //instance.send(0, "!!!!csv import - nedefinovane uniqueColumn");
+ //return;
+ }
+
+ if(!flowdata.data.hasOwnProperty("path"))
+ {
+ instance.send(0, "!!!!csv import - nedefinovana cesta k suboru");
+ return;
+ }
+
+ if(!flowdata.data.hasOwnProperty("mapImport"))
+ {
+ instance.send(0, "!!!!csv import - nedefinovany mapImport");
+ return;
+ }
+
+ table = flowdata.data.table;
+ uniqueColumn = flowdata.data.uniqueColumn;
+ if(uniqueColumn === "") uniqueColumn = undefined;
+
+ path = flowdata.data.path;
+ mapImport = flowdata.data.mapImport;
+
+ if(flowdata.data.hasOwnProperty("delimiter")) delimiter = flowdata.data.delimiter;
+ if(flowdata.data.hasOwnProperty("startFrom")) startFrom = flowdata.data.startFrom;
+ }
+
+
+ var db = TABLE(table);
+ db.clear();
+
+ let keys = Object.keys(mapImport);
+
+ try {
+ const data = fs.readFileSync(path, 'utf8')
+
+ let lines = data.split("\n");
+
+ for(let i = startFrom; i < lines.length; i++)
+ {
+ let line = lines[i];
+ if(line === "") continue;
+
+ let data = line.split(delimiter);
+ if(data.length == 0) continue;
+
+ let insertData = {};
+
+ keys.map(function(key){
+ let k = mapImport[key];
+
+ //console.log("importineg", i, key, k);
+
+ if(data[key] != undefined) insertData[k] = data[key].trim();
+ else{
+ console.log("undefined", key, data);
+ }
+ });
+
+ console.log("insertData", insertData);
+
+ if(uniqueColumn != undefined)
+ {
+ db.insert(insertData, true).where(uniqueColumn, insertData[uniqueColumn]);
+ }
+ else
+ {
+ db.insert(insertData);
+ }
+
+
+ }
+
+ console.log("csv import finished");
+ instance.send(0, "csv import finished");
+
+ } catch (err) {
+ console.error(err)
+ instance.send(0, err);
+ }
+ })
+
+}
+
+
diff --git a/flow/db_init.js b/flow/db_init.js
deleted file mode 100644
index 2a5caf9..0000000
--- a/flow/db_init.js
+++ /dev/null
@@ -1,124 +0,0 @@
-exports.id = 'db_init';
-exports.title = 'DB Initialization';
-exports.group = 'Worksys';
-exports.color = '#888600';
-exports.version = '1.0.2';
-exports.icon = 'sign-out';
-exports.output = 2;
-
-exports.html = `
-
-
-
Hostname or IP address (if not empty - setting will override db setting)
-
-
-
-
-
`;
-
-
-exports.readme = `
-# DB initialization
-`;
-
-const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
-const { initNotification } = require('./helper/notification_reporter');
-const errorHandler = require('./helper/ErrorToServiceHandler');
-
-const SEND_TO = {
- db_init: 0,
- infoSender: 1
-};
-
-
-exports.install = async function(instance) {
-
- const dbNodes = TABLE("nodes");
- const dbRelays = TABLE("relays");
- const dbSettings = TABLE("settings");
- const dbPins = TABLE("pins");
- const dbNotifications = TABLE("notifications");
-
- FLOW.GLOBALS = {};
- const dbs = FLOW.GLOBALS;
-
- const responseSettings = await promisifyBuilder(dbSettings.find());
- const responseNodes = await promisifyBuilder(dbNodes.find());
- const responsePins = await promisifyBuilder(dbPins.find());
- const responseRelays = await promisifyBuilder(dbRelays.find());
- const response = await promisifyBuilder(dbNotifications.find());
-
- dbs.pinsData = makeMapFromDbResult(responsePins, "pin");
- dbs.relaysData = makeMapFromDbResult(responseRelays, "line");
- dbs.nodesData = makeMapFromDbResult(responseNodes, "node");
- dbs.notificationsData = makeMapFromDbResult(response, "key");
-
- //+|354|nodesdata.....+|482|nodesdata....
- //for some reason, if last line in nodes.table is not empty, flow wrote more nodes data in one row,
- //so we have to add empty line at the bottom of nodes table to avoid this.
- //now, remove empty lines from nodesData database:
- if (dbs.nodesData.hasOwnProperty("0")) delete dbs.nodesData["0"];
- Object.keys(dbs.nodesData).forEach(node => dbs.nodesData[node].readout = {})
-
- dbs.settings = {
- edge_fw_version: "2025-04-24", //rok-mesiac-den
- language: responseSettings[0]["lang"],
- rvo_name: responseSettings[0]["rvo_name"],
- project_id: responseSettings[0]["project_id"],
- rvoTbName: dbs.relaysData[0]["tbname"],
- temperature_address: responseSettings[0]["temperature_address"],
- controller_type: responseSettings[0]["controller_type"],
- serial_port: responseSettings[0]["serial_port"],
- node_status_nok_time: responseSettings[0]["node_status_nok_time"] * 60 * 60 * 1000,// hour * minutes *
- latitude: responseSettings[0]["latitude"],
- longitude: responseSettings[0]["longitude"],
- no_voltage: new Set(),//modbus_citysys - elektromer
- backup_on_failure: responseSettings[0]["backup_on_failure"],
- restore_from_backup: responseSettings[0]["restore_from_backup"],
- restore_backup_wait: responseSettings[0]["restore_backup_wait"],
- mqtt_host: responseSettings[0]["mqtt_host"],
- mqtt_clientid: responseSettings[0]["mqtt_clientid"],
- mqtt_username: responseSettings[0]["mqtt_username"],
- mqtt_port: responseSettings[0]["mqtt_port"],
- phases: responseSettings[0]["phases"],
- cloud_topic: responseSettings[0]["cloud_topic"],
- has_main_switch: responseSettings[0]["has_main_switch"],
-
- //dynamic values
- masterNodeIsResponding: true, //cmd_manager
- maintenance_mode: false,
- }
-
- FLOW.dbLoaded = true;
- errorHandler.setProjectId(dbs.settings.project_id);
- initNotification();
-
- //APP START - send to data services
- const toService = {
- id: dbs.settings.project_id,
- name: dbs.settings.rvo_name,
- fw_version: dbs.settings.edge_fw_version,
- startdate: new Date().toISOString().slice(0, 19).replace('T', ' '),
- js_error: "",
- error_message: ""
- };
-
- instance.send(SEND_TO.infoSender, toService);
- console.log("----------------> START - message send to service", toService);
-
- setTimeout(() => {
- console.log("DB_INIT - data loaded");
- instance.send(SEND_TO.db_init, "_")
- }, 5000)
-
-};
-
diff --git a/flow/designer.json b/flow/designer.json
index e5d2a7c..7d57d69 100644
--- a/flow/designer.json
+++ b/flow/designer.json
@@ -25,8 +25,8 @@
"component": "debug",
"tab": "1611921777196",
"name": "ERROR",
- "x": 598,
- "y": 60,
+ "x": 401,
+ "y": 31,
"connections": {},
"disabledio": {
"input": [],
@@ -36,21 +36,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#DA4453",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#DA4453",
+ "notes": ""
},
{
"id": "1612776786008",
"component": "wsmqttpublish",
"tab": "1612772287426",
"name": "WS MQTT publish",
- "x": 281.75,
- "y": 174,
+ "x": 311.75,
+ "y": 248,
"connections": {
"0": [
{
@@ -71,13 +71,11 @@
"2": [
{
"index": "0",
- "id": "1634303685503"
- }
- ],
- "3": [
+ "id": "1618300863816"
+ },
{
"index": "0",
- "id": "1731068754606"
+ "id": "1634303685503"
}
]
},
@@ -89,35 +87,31 @@
"text": "Connected",
"color": "green"
},
- "color": "#888600",
- "notes": "",
"options": {
"username": "",
"clientid": "",
"port": "1883",
"host": ""
- }
+ },
+ "color": "#888600",
+ "notes": ""
},
{
"id": "1612778461252",
"component": "virtualwirein",
"tab": "1612772287426",
"name": "tb-push",
- "x": 72.75,
- "y": 328,
+ "x": 68.75,
+ "y": 269,
"connections": {
"0": [
{
"index": "0",
- "id": "1612783322136"
- },
- {
- "index": "1",
"id": "1612776786008"
},
{
"index": "0",
- "id": "1731068754606"
+ "id": "1612783322136"
}
]
},
@@ -129,43 +123,19 @@
"text": "tb-push",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "tb-push"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1612783322136",
"component": "debug",
"tab": "1612772287426",
"name": "to TB",
- "x": 283.75,
- "y": 324,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615551060773",
- "component": "debug",
- "tab": "1612772287426",
- "name": "errors from MQTT Broker",
- "x": 594,
- "y": 57,
+ "x": 317.75,
+ "y": 154,
"connections": {},
"disabledio": {
"input": [
@@ -177,13 +147,39 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#DA4453",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1615551060773",
+ "component": "debug",
+ "tab": "1612772287426",
+ "name": "errors from MQTT Broker",
+ "x": 610,
+ "y": 111,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#DA4453",
+ "notes": ""
},
{
"id": "1615563373927",
@@ -191,7 +187,7 @@
"tab": "1615551125555",
"name": "Debug",
"x": 755,
- "y": 155,
+ "y": 19,
"connections": {},
"disabledio": {
"input": [
@@ -203,21 +199,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#DA4453",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#DA4453",
+ "notes": ""
},
{
"id": "1615566865233",
"component": "virtualwireout",
"tab": "1615551125555",
"name": "tb-push",
- "x": 755,
- "y": 248,
+ "x": 753,
+ "y": 112,
"connections": {},
"disabledio": {
"input": [],
@@ -227,19 +223,19 @@
"text": "tb-push",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "tb-push"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1615798582262",
"component": "debug",
"tab": "1615551125555",
"name": "CMD_debug",
- "x": 755,
- "y": 346,
+ "x": 750,
+ "y": 197,
"connections": {},
"disabledio": {
"input": [
@@ -251,69 +247,73 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1615802995322",
"component": "debug",
"tab": "1611921777196",
"name": "Debug",
- "x": 596.8833312988281,
- "y": 566.3500061035156,
+ "x": 398.8833312988281,
+ "y": 528.3500061035156,
"connections": {},
"disabledio": {
- "input": [],
+ "input": [
+ 0
+ ],
"output": []
},
"state": {
"text": "Disabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": false
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1615809128443",
"component": "debug",
"tab": "1611921777196",
- "name": "tempToTb",
- "x": 595.8833312988281,
- "y": 658.3500061035156,
+ "name": "Debug",
+ "x": 401.8833312988281,
+ "y": 625.3500061035156,
"connections": {},
"disabledio": {
- "input": [],
+ "input": [
+ 0
+ ],
"output": []
},
"state": {
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1615809595184",
"component": "virtualwireout",
"tab": "1611921777196",
"name": "tb-push",
- "x": 597.8833312988281,
- "y": 377.25,
+ "x": 400.8833312988281,
+ "y": 328.25,
"connections": {},
"disabledio": {
"input": [],
@@ -323,28 +323,28 @@
"text": "tb-push",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "tb-push"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1616165795916",
"component": "httproute",
"tab": "1615551125555",
"name": "POST /terminal",
- "x": 135,
- "y": 547,
+ "x": 72,
+ "y": 350,
"connections": {
"0": [
{
"index": "0",
- "id": "1684060205000"
+ "id": "1619515097737"
},
{
- "index": "1",
- "id": "1619515097737"
+ "index": "0",
+ "id": "1684060205000"
}
]
},
@@ -356,9 +356,6 @@
"text": "Listening",
"color": "green"
},
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
"options": {
"timeout": 10,
"cachepolicy": 0,
@@ -368,20 +365,23 @@
"method": "POST",
"name": "",
"flags": [
- 10000,
"id:1616165795916",
- "post"
+ "post",
+ 10000
],
"emptyresponse": false
- }
+ },
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false
},
{
"id": "1616165824813",
"component": "httpresponse",
"tab": "1615551125555",
"name": "HTTP Response",
- "x": 753,
- "y": 423,
+ "x": 751,
+ "y": 273,
"connections": {},
"disabledio": {
"input": [],
@@ -391,19 +391,19 @@
"text": "",
"color": "gray"
},
- "color": "#5D9CEC",
- "notes": "",
"options": {
"datatype": "json"
- }
+ },
+ "color": "#5D9CEC",
+ "notes": ""
},
{
"id": "1617104731852",
"component": "debug",
"tab": "1615551125555",
"name": "DIDO_Debug",
- "x": 669,
- "y": 1040,
+ "x": 739,
+ "y": 635,
"connections": {},
"disabledio": {
"input": [
@@ -415,21 +415,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1617114651703",
"component": "trigger",
"tab": "1615551125555",
"name": "turnOff line",
- "x": 133,
- "y": 1161,
+ "x": 71,
+ "y": 829,
"connections": {
"0": [
{
@@ -446,20 +446,20 @@
"text": "",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
- "datatype": "object",
- "data": "{line: 2, command: \"off\", force: true}"
- }
+ "data": "{line: 3, command: \"turnOff\", force: true}",
+ "datatype": "object"
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1617115013095",
"component": "virtualwireout",
"tab": "1615551125555",
"name": "tb-push",
- "x": 669,
- "y": 1150,
+ "x": 741,
+ "y": 736,
"connections": {},
"disabledio": {
"input": [],
@@ -469,78 +469,19 @@
"text": "tb-push",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "tb-push"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
- "id": "1617284749681",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "update profile / node",
- "x": 112,
- "y": 208,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "profile_nodes",
- "datatype": "string"
- }
- },
- {
- "id": "1618235171399",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "tun tasks",
- "x": 184,
- "y": 279,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "run"
- }
- },
- {
- "id": "1618300858252",
+ "id": "1617178324650",
"component": "debug",
- "tab": "1612772287426",
- "name": "wsmqtt-exit1",
- "x": 597.8833312988281,
- "y": 149,
+ "tab": "1615551125555",
+ "name": "Debug",
+ "x": 605,
+ "y": 1024,
"connections": {},
"disabledio": {
"input": [],
@@ -550,21 +491,209 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
+ },
+ {
+ "id": "1617179044099",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "start import",
+ "x": 235,
+ "y": 1032,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1617180390661"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "datatype": "object",
+ "data": "{table: \"konsberg_production_line_operations_error\", startFrom: 1, delimiter: \";\", uniqueColumn: \"\", path: \"flow/operations_error.csv\", mapImport: {0: \"production_line\",\t1: \"operation\", 2: \"error_type\", 3: \"error_code\", 4: \"error_text\", 5: \"error_text_user_defined\"}}"
+ },
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1617180390661",
+ "component": "csv_import",
+ "tab": "1615551125555",
+ "name": "CsvImport",
+ "x": 414,
+ "y": 1013,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1617178324650"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "edge": "undefined"
+ },
+ "color": "#2134B0",
+ "notes": ""
+ },
+ {
+ "id": "1617197763128",
+ "component": "comment",
+ "tab": "1615551125555",
+ "name": "import data from csv",
+ "x": 401,
+ "y": 946,
+ "connections": {},
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {},
+ "color": "#704cff",
+ "notes": ""
+ },
+ {
+ "id": "1617284749681",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "update profile / node",
+ "x": 80,
+ "y": 13,
+ "connections": {
+ "0": [
+ {
+ "index": "0",
+ "id": "1619515097737"
+ }
+ ]
+ },
+ "disabledio": {
+ "input": [],
+ "output": []
+ },
+ "state": {
+ "text": "",
+ "color": "gray"
+ },
+ "options": {
+ "datatype": "string",
+ "data": "profile_nodes"
+ },
+ "color": "#F6BB42",
+ "notes": ""
+ },
+ {
+ "id": "1618235171399",
+ "component": "trigger",
+ "tab": "1615551125555",
+ "name": "tun tasks",
+ "x": 77,
+ "y": 84,
+ "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": 610.8833312988281,
+ "y": 199,
+ "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": 611.8833312988281,
+ "y": 374,
+ "connections": {},
+ "disabledio": {
+ "input": [
+ 0
+ ],
+ "output": []
+ },
+ "state": {
+ "text": "Enabled",
+ "color": "gray"
+ },
+ "options": {
+ "type": "data",
+ "repository": false,
+ "enabled": true
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1618393583970",
"component": "virtualwireout",
"tab": "1615551125555",
"name": "to-cmd-manager",
- "x": 668.8833312988281,
- "y": 1269,
+ "x": 740.8833312988281,
+ "y": 828,
"connections": {},
"disabledio": {
"input": [],
@@ -574,23 +703,23 @@
"text": "from-dido-controller",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "from-dido-controller"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1618393674428",
"component": "virtualwirein",
"tab": "1615551125555",
"name": "platform-rpc-call",
- "x": 132.88333129882812,
- "y": 367,
+ "x": 77.88333129882812,
+ "y": 173,
"connections": {
"0": [
{
- "index": "1",
+ "index": "0",
"id": "1619515097737"
}
]
@@ -603,19 +732,19 @@
"text": "platform-rpc-call",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "platform-rpc-call"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1618393759854",
"component": "virtualwirein",
"tab": "1615551125555",
"name": "cmd_to_dido",
- "x": 119.88333129882812,
- "y": 1007,
+ "x": 76.88333129882812,
+ "y": 678,
"connections": {
"0": [
{
@@ -636,19 +765,19 @@
"text": "cmd_to_dido",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "cmd_to_dido"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1618393827655",
"component": "virtualwireout",
"tab": "1615551125555",
"name": "cmd_to_dido",
- "x": 752.8833312988281,
- "y": 527,
+ "x": 748.8833312988281,
+ "y": 373,
"connections": {},
"disabledio": {
"input": [],
@@ -658,19 +787,19 @@
"text": "cmd_to_dido",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "cmd_to_dido"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1618558465485",
"component": "virtualwireout",
"tab": "1612772287426",
"name": "platform-rpc-call",
- "x": 597.8833312988281,
- "y": 247,
+ "x": 611.8833312988281,
+ "y": 287,
"connections": {},
"disabledio": {
"input": [],
@@ -680,19 +809,19 @@
"text": "platform-rpc-call",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "platform-rpc-call"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1618572059773",
"component": "trigger",
"tab": "1615551125555",
"name": "turnOn line",
- "x": 132,
- "y": 1085,
+ "x": 72,
+ "y": 756,
"connections": {
"0": [
{
@@ -709,20 +838,20 @@
"text": "",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
- "data": "{line: 2, command: \"on\", force: true}",
- "datatype": "object"
- }
+ "datatype": "object",
+ "data": "{line: 1, command: \"turnOn\", force: true}"
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1619515097737",
"component": "cmd_manager",
"tab": "1615551125555",
"name": "CMD Manager",
- "x": 452.1091003417969,
- "y": 341.05455017089844,
+ "x": 420,
+ "y": 156,
"connections": {
"0": [
{
@@ -767,26 +896,26 @@
"text": "",
"color": "gray"
},
+ "options": {},
"color": "#5D9CEC",
- "notes": "",
- "options": {}
+ "notes": ""
},
{
"id": "1619605019281",
"component": "httproute",
"tab": "1615551125555",
"name": "GET db",
- "x": 173,
- "y": 653,
+ "x": 73,
+ "y": 455,
"connections": {
"0": [
{
"index": "0",
- "id": "1684060205000"
+ "id": "1619515097737"
},
{
- "index": "1",
- "id": "1619515097737"
+ "index": "0",
+ "id": "1684060205000"
}
]
},
@@ -798,9 +927,6 @@
"text": "Listening",
"color": "green"
},
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
"options": {
"timeout": 5,
"cachepolicy": 0,
@@ -810,19 +936,22 @@
"method": "GET",
"name": "",
"flags": [
- 5000,
"id:1619605019281",
- "get"
+ "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": 120,
- "y": 1234,
+ "x": 68,
+ "y": 902,
"connections": {
"0": [
{
@@ -839,20 +968,20 @@
"text": "",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
- "datatype": "object",
- "data": "{command: \"turnOnAlarm\"}"
- }
+ "data": "{command: \"turnOnAlarm\"}",
+ "datatype": "object"
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1619784812964",
"component": "trigger",
"tab": "1615551125555",
"name": "turnOffAlarm",
- "x": 118,
- "y": 1307,
+ "x": 67,
+ "y": 975,
"connections": {
"0": [
{
@@ -869,20 +998,20 @@
"text": "",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
- "datatype": "object",
- "data": "{command: \"turnOffAlarm\"}"
- }
+ "data": "{command: \"turnOffAlarm\"}",
+ "datatype": "object"
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1621340721628",
"component": "virtualwireout",
"tab": "1611921777196",
"name": "modbus_to_dido",
- "x": 599,
- "y": 471,
+ "x": 399,
+ "y": 433,
"connections": {},
"disabledio": {
"input": [],
@@ -892,19 +1021,19 @@
"text": "modbus_to_dido",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "modbus_to_dido"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1622640022885",
"component": "httproute",
"tab": "1615551125555",
"name": "POST /db_connector",
- "x": 98,
- "y": 1586,
+ "x": 1107,
+ "y": 338,
"connections": {
"0": [
{
@@ -921,9 +1050,6 @@
"text": "Listening",
"color": "green"
},
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
"options": {
"timeout": 5,
"cachepolicy": 0,
@@ -932,19 +1058,22 @@
"url": "/db_connector",
"method": "POST",
"flags": [
- 5000,
"id:1622640022885",
- "post"
+ "post",
+ 5000
]
- }
+ },
+ "color": "#5D9CEC",
+ "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
+ "cloning": false
},
{
"id": "1622640073521",
"component": "db_connector",
"tab": "1615551125555",
"name": "DbConnector",
- "x": 372,
- "y": 1572,
+ "x": 1363,
+ "y": 395,
"connections": {
"1": [
{
@@ -961,19 +1090,19 @@
"text": "",
"color": "gray"
},
- "color": "#2134B0",
- "notes": "",
"options": {
"edge": "undefined"
- }
+ },
+ "color": "#2134B0",
+ "notes": ""
},
{
"id": "1622641420685",
"component": "httpresponse",
"tab": "1615551125555",
"name": "HTTP Response",
- "x": 596,
- "y": 1586,
+ "x": 1588,
+ "y": 454,
"connections": {},
"disabledio": {
"input": [],
@@ -983,17 +1112,17 @@
"text": "",
"color": "gray"
},
+ "options": {},
"color": "#5D9CEC",
- "notes": "",
- "options": {}
+ "notes": ""
},
{
"id": "1634303504177",
"component": "monitormemory",
"tab": "1612772287426",
"name": "RAM",
- "x": 69.88333129882812,
- "y": 888.5,
+ "x": 71.88333129882812,
+ "y": 609.5,
"connections": {
"0": [
{
@@ -1007,23 +1136,23 @@
"output": []
},
"state": {
- "text": "595.82 MB / 982.12 MB",
+ "text": "834.19 MB / 985.68 MB",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
"enabled": true,
"interval": 30000
- }
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1634303533779",
"component": "monitordisk",
"tab": "1612772287426",
"name": "disk",
- "x": 70.88333129882812,
- "y": 982.5,
+ "x": 72.88333129882812,
+ "y": 706.5,
"connections": {
"0": [
{
@@ -1037,24 +1166,24 @@
"output": []
},
"state": {
- "text": "3.80 GB / 6.86 GB",
+ "text": "5.84 GB / 7.26 GB",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
"enabled": true,
"path": "/",
"interval": 30000
- }
+ },
+ "color": "#F6BB42",
+ "notes": ""
},
{
"id": "1634303595494",
"component": "virtualwirein",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 51.883331298828125,
- "y": 1400.5,
+ "x": 5.883331298828125,
+ "y": 1069.5,
"connections": {
"0": [
{
@@ -1062,7 +1191,7 @@
"id": "1634463186563"
},
{
- "index": "1",
+ "index": "0",
"id": "1634488120710"
}
]
@@ -1075,19 +1204,19 @@
"text": "send-to-services",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "send-to-services"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1634303602169",
"component": "virtualwireout",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 426.8833312988281,
- "y": 878.5,
+ "x": 428.8833312988281,
+ "y": 602.5,
"connections": {},
"disabledio": {
"input": [],
@@ -1097,19 +1226,19 @@
"text": "send-to-services",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "send-to-services"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1634303685503",
"component": "virtualwireout",
"tab": "1612772287426",
"name": "send-to-services",
- "x": 600.8833312988281,
- "y": 341.5,
+ "x": 612.8833312988281,
+ "y": 462.5,
"connections": {},
"disabledio": {
"input": [],
@@ -1119,20 +1248,20 @@
"text": "send-to-services",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "send-to-services"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1634303743260",
"component": "httprequest",
"tab": "1612772287426",
- "name": "192.168.252.2:8004/sentmessage",
+ "name": "http://192.168.252.2:8004/sentmessage",
"reference": "",
- "x": 506.8833312988281,
- "y": 1331.7333374023438,
+ "x": 439.8833312988281,
+ "y": 1076.7333374023438,
"connections": {
"0": [
{
@@ -1149,21 +1278,21 @@
"text": "",
"color": "gray"
},
- "color": "#5D9CEC",
- "notes": "",
"options": {
- "url": "http://192.168.252.2:8004/sentmessage",
+ "stringify": "json",
"method": "POST",
- "stringify": "json"
- }
+ "url": "http://192.168.252.2:8004/sentmessage"
+ },
+ "color": "#5D9CEC",
+ "notes": ""
},
{
"id": "1634463186563",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 305.75,
- "y": 1442,
+ "x": 234.75,
+ "y": 1024,
"connections": {},
"disabledio": {
"input": [
@@ -1175,21 +1304,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1634464580289",
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 245,
- "y": 787,
+ "x": 255,
+ "y": 512,
"connections": {
"0": [
{
@@ -1210,21 +1339,21 @@
"text": "",
"color": "gray"
},
- "color": "#656D78",
- "notes": "",
"options": {
"keepmessage": true,
"code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);",
"outputs": 1
- }
+ },
+ "color": "#656D78",
+ "notes": ""
},
{
"id": "1634465243324",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 428,
- "y": 784,
+ "x": 430,
+ "y": 508,
"connections": {},
"disabledio": {
"input": [
@@ -1236,21 +1365,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1634465281992",
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 245,
- "y": 884,
+ "x": 244,
+ "y": 608,
"connections": {
"0": [
{
@@ -1271,21 +1400,21 @@
"text": "",
"color": "gray"
},
- "color": "#656D78",
- "notes": "",
"options": {
"keepmessage": true,
- "code": "value.sender = \"ram\";\n\nlet response = {};\n\nresponse.memory_total = Math.round(value.total / (1024 ** 2));\nresponse.memory_free = Math.round(value.free / (1024 ** 2));\nresponse.memory_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
+ "code": "value.sender = \"ram\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.memory_total = (total).toFixed(0) + ' MB';\n//value.memory_free = (free).toFixed(0) + ' MB';\n//value.memory_used = (used).toFixed(0) + ' MB';\n\nresponse.memory_total = value.total;\nresponse.memory_free = value.free;\nresponse.memory_used = value.used;\n\nsend(0, response);",
"outputs": 1
- }
+ },
+ "color": "#656D78",
+ "notes": ""
},
{
"id": "1634465338103",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 429,
- "y": 976,
+ "x": 431,
+ "y": 700,
"connections": {},
"disabledio": {
"input": [
@@ -1297,21 +1426,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1634465821120",
"component": "code",
"tab": "1612772287426",
"name": "Code",
- "x": 245,
- "y": 978,
+ "x": 247,
+ "y": 702,
"connections": {
"0": [
{
@@ -1332,21 +1461,21 @@
"text": "",
"color": "gray"
},
- "color": "#656D78",
- "notes": "",
"options": {
"keepmessage": true,
- "code": "value.sender = \"hdd\";\n\nlet response = {};\n\nresponse.hdd_total = Math.round(value.total / (1024 ** 2));\nresponse.hdd_free = Math.round(value.free / (1024 ** 2));\nresponse.hdd_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
+ "code": "value.sender = \"hdd\";\n//let total = value.total/1024/1024;\n//let free = value.free/1024/1024;\n//let used = value.used/1024/1024;\nlet response = {};\n//value.hdd_total = (total).toFixed(0) + ' MB';\n//value.hdd_free = (free).toFixed(0) + ' MB';\n//value.used = (used).toFixed(0) + ' MB';\n\nresponse.hdd_total = value.total;\nresponse.hdd_free = value.free;\nresponse.hdd_used = value.used;\n\nsend(0, response);",
"outputs": 1
- }
+ },
+ "color": "#656D78",
+ "notes": ""
},
{
"id": "1634465892500",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 432,
- "y": 1068,
+ "x": 434,
+ "y": 792,
"connections": {},
"disabledio": {
"input": [
@@ -1358,21 +1487,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1634484067516",
"component": "debug",
"tab": "1612772287426",
"name": "Send info",
- "x": 513,
- "y": 1441,
+ "x": 438,
+ "y": 1185,
"connections": {},
"disabledio": {
"input": [
@@ -1384,21 +1513,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1634488120710",
"component": "infosender",
"tab": "1612772287426",
"name": "Info sender",
- "x": 301,
- "y": 1336,
+ "x": 233,
+ "y": 1122,
"connections": {
"0": [
{
@@ -1419,19 +1548,19 @@
"text": "",
"color": "gray"
},
- "color": "#2134B0",
- "notes": "",
"options": {
"edge": "undefined"
- }
+ },
+ "color": "#2134B0",
+ "notes": ""
},
{
"id": "1635327431236",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 837.8833312988281,
- "y": 1325.5,
+ "x": 811.8833312988281,
+ "y": 1070.5,
"connections": {},
"disabledio": {
"input": [
@@ -1443,21 +1572,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1635936391935",
"component": "virtualwireout",
"tab": "1615551125555",
"name": "send-to-services",
- "x": 753,
- "y": 623,
+ "x": 748,
+ "y": 464,
"connections": {},
"disabledio": {
"input": [],
@@ -1467,19 +1596,19 @@
"text": "send-to-services",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "send-to-services"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1637069803394",
"component": "monitorconsumption",
"tab": "1612772287426",
"name": "CPU",
- "x": 69,
- "y": 791,
+ "x": 71,
+ "y": 515,
"connections": {
"0": [
{
@@ -1493,11 +1622,9 @@
"output": []
},
"state": {
- "text": "2.8% / 99.24 MB",
+ "text": "1.9% / 86.94 MB",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"monitorfiles": true,
"monitorconnections": true,
@@ -1505,15 +1632,17 @@
"monitorconsumption": true,
"enabled": true,
"interval": 30000
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1683664161036",
"component": "debug",
"tab": "1615551125555",
"name": "CMDtoDIDO",
- "x": 392,
- "y": 1012,
+ "x": 413,
+ "y": 654,
"connections": {},
"disabledio": {
"input": [
@@ -1525,30 +1654,30 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1683981346282",
"component": "virtualwirein",
"tab": "1615551125555",
"name": "from-dido-controller",
- "x": 112,
- "y": 459,
+ "x": 71,
+ "y": 260,
"connections": {
"0": [
{
"index": "0",
- "id": "1684055037116"
+ "id": "1619515097737"
},
{
- "index": "1",
- "id": "1619515097737"
+ "index": "0",
+ "id": "1684055037116"
}
]
},
@@ -1560,19 +1689,19 @@
"text": "from-dido-controller",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "from-dido-controller"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1684055037116",
"component": "debug",
"tab": "1615551125555",
"name": "from dido to cmd",
- "x": 451,
- "y": 532,
+ "x": 423,
+ "y": 331,
"connections": {},
"disabledio": {
"input": [
@@ -1584,21 +1713,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1684060205000",
"component": "debug",
"tab": "1615551125555",
"name": "HTTP routes",
- "x": 450,
- "y": 639,
+ "x": 423,
+ "y": 422,
"connections": {},
"disabledio": {
"input": [
@@ -1610,21 +1739,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1684179110403",
"component": "debug",
"tab": "1611921777196",
"name": "MDBToDido",
- "x": 598,
- "y": 147,
+ "x": 401,
+ "y": 118,
"connections": {},
"disabledio": {
"input": [],
@@ -1634,21 +1763,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1699963668903",
"component": "dido_controller",
"tab": "1615551125555",
"name": "DIDO_Controller",
- "x": 397,
- "y": 1131,
+ "x": 402,
+ "y": 736,
"connections": {
"0": [
{
@@ -1681,19 +1810,19 @@
"text": "",
"color": "gray"
},
- "color": "#2134B0",
- "notes": "",
"options": {
"edge": "undefined"
- }
+ },
+ "color": "#2134B0",
+ "notes": ""
},
{
"id": "1699964678894",
"component": "virtualwirein",
"tab": "1615551125555",
"name": "modbus_to_dido",
- "x": 96,
- "y": 924,
+ "x": 79,
+ "y": 595,
"connections": {
"0": [
{
@@ -1714,19 +1843,19 @@
"text": "modbus_to_dido",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "modbus_to_dido"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1699964793925",
"component": "debug",
"tab": "1615551125555",
"name": "modbusToDido",
- "x": 388,
- "y": 920,
+ "x": 411,
+ "y": 561,
"connections": {},
"disabledio": {
"input": [
@@ -1738,20 +1867,20 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1699965957410",
"component": "modbus_reader",
"tab": "1611921777196",
"name": "Modbus reader",
- "x": 232,
+ "x": 102,
"y": 175,
"connections": {
"0": [
@@ -1793,17 +1922,17 @@
"text": "",
"color": "gray"
},
+ "options": {},
"color": "#2134B0",
- "notes": "",
- "options": {}
+ "notes": ""
},
{
"id": "1700411878636",
"component": "thermometer",
"tab": "1611921777196",
"name": "Thermometer",
- "x": 234.75,
- "y": 444,
+ "x": 107.75,
+ "y": 449,
"connections": {
"0": [
{
@@ -1825,14 +1954,6 @@
{
"index": "0",
"id": "1621340721628"
- },
- {
- "index": "0",
- "id": "1732889185927"
- },
- {
- "index": "0",
- "id": "1717441414646"
}
]
},
@@ -1844,17 +1965,17 @@
"text": "",
"color": "gray"
},
+ "options": {},
"color": "#5CB36D",
- "notes": "",
- "options": {}
+ "notes": ""
},
{
"id": "1714752862828",
"component": "debug",
"tab": "1611921777196",
"name": "MDBToTb",
- "x": 766,
- "y": 324,
+ "x": 402,
+ "y": 228,
"connections": {},
"disabledio": {
"input": [],
@@ -1864,21 +1985,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1717441414646",
"component": "code",
"tab": "1611921777196",
"name": "device-status",
- "x": 764.0833282470703,
- "y": 222,
+ "x": 588.0833282470703,
+ "y": 177,
"connections": {
"0": [
{
@@ -1899,21 +2020,21 @@
"text": "",
"color": "gray"
},
- "color": "#656D78",
- "notes": "",
"options": {
"keepmessage": true,
- "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n\telse if(value.status === \"NOK-thermometer\")\n\t{\n\t\tsend(0, {\"thermometer\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"temperature\"))\n\t{\n\t\tsend(0, {\"thermometer\": \"OK\"});\n\t}\n}",
+ "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n}",
"outputs": 1
- }
+ },
+ "color": "#656D78",
+ "notes": ""
},
{
"id": "1717442627834",
"component": "debug",
"tab": "1611921777196",
"name": "modbus service",
- "x": 966.0833282470703,
- "y": 165,
+ "x": 802.0833282470703,
+ "y": 139,
"connections": {},
"disabledio": {
"input": [
@@ -1925,21 +2046,21 @@
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1717442631338",
"component": "virtualwireout",
"tab": "1611921777196",
"name": "send-to-services",
- "x": 968.0833282470703,
- "y": 268,
+ "x": 801.0833282470703,
+ "y": 236,
"connections": {},
"disabledio": {
"input": [],
@@ -1949,19 +2070,19 @@
"text": "send-to-services",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "send-to-services"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1718016045116",
"component": "virtualwirein",
"tab": "1612772287426",
"name": "tb-push",
- "x": 77.75,
- "y": 1630,
+ "x": 84.75,
+ "y": 1300,
"connections": {
"0": [
{
@@ -1978,19 +2099,19 @@
"text": "tb-push",
"color": "gray"
},
- "color": "#303E4D",
- "notes": "",
"options": {
"wirename": "tb-push"
- }
+ },
+ "color": "#303E4D",
+ "notes": ""
},
{
"id": "1718016052341",
"component": "slack_filter",
"tab": "1612772287426",
"name": "Slack Filter",
- "x": 296,
- "y": 1671,
+ "x": 278,
+ "y": 1297,
"connections": {
"0": [
{
@@ -2011,23 +2132,23 @@
"text": "Running",
"color": "gray"
},
- "color": "#30E193",
- "notes": "",
"options": {
"slack_channel": "C071KN2Q8SK",
"tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
- "message_includes": "[\"is responding again\", \"Flow has been restarted\", \"Node db has changed\"]",
+ "message_includes": "[\"is responding again\", \"Lamps have turned\", \"Flow has been restarted\"]",
"types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
- "name": "test_rvo_debian12"
- }
+ "name": "RVO16 Senica - 10.0.0.131"
+ },
+ "color": "#30E193",
+ "notes": ""
},
{
"id": "1718016073501",
"component": "httprequest",
"tab": "1612772287426",
"name": "http://192.168.252.2:8004/slack",
- "x": 495,
- "y": 1753,
+ "x": 471,
+ "y": 1354,
"connections": {
"0": [
{
@@ -2044,47 +2165,45 @@
"text": "",
"color": "gray"
},
- "color": "#5D9CEC",
- "notes": "",
"options": {
- "url": "http://192.168.252.2:8004/slack",
+ "stringify": "json",
"method": "POST",
- "stringify": "json"
- }
+ "url": "http://192.168.252.2:8004/slack"
+ },
+ "color": "#5D9CEC",
+ "notes": ""
},
{
"id": "1718016086212",
"component": "debug",
"tab": "1612772287426",
"name": "Debug",
- "x": 832,
- "y": 1664,
+ "x": 808,
+ "y": 1302,
"connections": {},
"disabledio": {
- "input": [
- 0
- ],
+ "input": [],
"output": []
},
"state": {
"text": "Enabled",
"color": "gray"
},
- "color": "#967ADC",
- "notes": "",
"options": {
"type": "data",
"repository": false,
"enabled": true
- }
+ },
+ "color": "#967ADC",
+ "notes": ""
},
{
"id": "1718016094070",
"component": "trigger",
"tab": "1612772287426",
"name": "Trigger",
- "x": 79,
- "y": 1723,
+ "x": 73,
+ "y": 1388,
"connections": {
"0": [
{
@@ -2101,793 +2220,13 @@
"text": "",
"color": "gray"
},
- "color": "#F6BB42",
- "notes": "",
"options": {
- "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }",
- "datatype": "object"
- }
- },
- {
- "id": "1729855334955",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "platform-rpc-call",
- "x": 599.9333343505859,
- "y": 541.3500061035156,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "platform-rpc-call",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "platform-rpc-call"
- }
- },
- {
- "id": "1729855371093",
- "component": "debug",
- "tab": "1612772287426",
- "name": "rpc cloud",
- "x": 601.9333343505859,
- "y": 440.3500061035156,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1731068658334",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 75.75,
- "y": 184,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1612776786008"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731068754606",
- "component": "cloudmqttconnect",
- "tab": "1612772287426",
- "name": "MQTT to senica-prod01",
- "x": 284.75,
- "y": 452,
- "connections": {
- "1": [
- {
- "index": "0",
- "id": "1729855371093"
- },
- {
- "index": "0",
- "id": "1729855334955"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Connected",
- "color": "green"
- },
- "color": "#888600",
- "notes": "",
- "options": {
- "username": "",
- "clientid": "",
- "port": "2764",
- "host": "192.168.252.2",
- "topic": "u38"
- }
- },
- {
- "id": "1731069001548",
- "component": "db_init",
- "tab": "1612772287426",
- "name": "DB Initialization",
- "x": 1003.75,
- "y": 240.25,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069033416"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1747561603739"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069033416",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 1244.75,
- "y": 233.25,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069059135",
- "component": "showdb",
- "tab": "1612772287426",
- "name": "Show db data",
- "x": 1186.75,
- "y": 821.25,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069079243"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069079243",
- "component": "debug",
- "tab": "1612772287426",
- "name": "dbData",
- "x": 1390.75,
- "y": 870.25,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1731069116691",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "settings",
- "x": 934.75,
- "y": 669.75,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
+ "datatype": "object",
+ "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }"
},
"color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069131637",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "relaysData",
- "x": 876.75,
- "y": 733.75,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069137374",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "nodesData",
- "x": 852.75,
- "y": 794.75,
- "connections": {
- "0": [
- {
- "index": "2",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069179846",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "pinsData",
- "x": 850.75,
- "y": 861.75,
- "connections": {
- "0": [
- {
- "index": "3",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069192937",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "sample data",
- "x": 857.75,
- "y": 928.75,
- "connections": {
- "0": [
- {
- "index": "4",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069264443",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 63.75,
- "y": 1279,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634488120710"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069334626",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "db-init",
- "x": 172.88333129882812,
- "y": 129,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069548145",
- "component": "virtualwirein",
- "tab": "1611921777196",
- "name": "db-init",
- "x": 46.75,
- "y": 192,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1699965957410"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069567152",
- "component": "virtualwirein",
- "tab": "1611921777196",
- "name": "db-init",
- "x": 44.75,
- "y": 465,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1700411878636"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731070156936",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "db-init",
- "x": 126.88333129882812,
- "y": 1377,
- "connections": {
- "0": [
- {
- "index": "2",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731234189516",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "monitor.txt",
- "x": 882.75,
- "y": 991.75,
- "connections": {
- "0": [
- {
- "index": "5",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731234189551",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "err.txt",
- "x": 904.75,
- "y": 1053.75,
- "connections": {
- "0": [
- {
- "index": "6",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1732700042559",
- "component": "nodesdb_change_check",
- "tab": "1612772287426",
- "name": "Nodes DB change check",
- "x": 263.8833312988281,
- "y": 1993.2333984375,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1732700071298"
- },
- {
- "index": "0",
- "id": "1732700642917"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1732700057052",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 84.75,
- "y": 1994,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1732700042559"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1732700071298",
- "component": "debug",
- "tab": "1612772287426",
- "name": "nodesChange",
- "x": 561.8833312988281,
- "y": 2055.2333984375,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1732700642917",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "tb-push",
- "x": 557.8833312988281,
- "y": 1949,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1732889185927",
- "component": "debug",
- "tab": "1611921777196",
- "name": "tempToDido",
- "x": 594.8833312988281,
- "y": 753,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1733574412965",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 72.75,
- "y": 474,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1731068754606"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1747561603739",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "send-to-services",
- "x": 1243.8833312988281,
- "y": 334.5,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1747562867845",
- "component": "comment",
- "tab": "1612772287426",
- "name": "FLOW STARTING POINT",
- "x": 1003.5666656494141,
- "y": 178,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#704cff",
- "notes": "",
- "options": {}
- },
- {
- "id": "1749211698385",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "deviceStatus",
- "x": 911.75,
- "y": 1116.75,
- "connections": {
- "0": [
- {
- "index": "7",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
+ "notes": ""
}
],
- "version": 624
+ "version": 615
}
\ No newline at end of file
diff --git a/flow/designer.json_orig b/flow/designer.json_orig
deleted file mode 100644
index eb18e86..0000000
--- a/flow/designer.json_orig
+++ /dev/null
@@ -1,2775 +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": "1611951142547",
- "component": "debug",
- "tab": "1611921777196",
- "name": "ERROR",
- "x": 598,
- "y": 60,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#DA4453",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1612776786008",
- "component": "wsmqttpublish",
- "tab": "1612772287426",
- "name": "WS MQTT publish",
- "x": 290.75,
- "y": 189,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1615551060773"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1618300858252"
- },
- {
- "index": "0",
- "id": "1618558465485"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1634303685503"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Connected",
- "color": "green"
- },
- "color": "#888600",
- "notes": "",
- "options": {
- "username": "",
- "clientid": "",
- "port": "1883",
- "host": ""
- }
- },
- {
- "id": "1612778461252",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "tb-push",
- "x": 72.75,
- "y": 328,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1612783322136"
- },
- {
- "index": "1",
- "id": "1612776786008"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1612783322136",
- "component": "debug",
- "tab": "1612772287426",
- "name": "to TB",
- "x": 290.75,
- "y": 330,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615551060773",
- "component": "debug",
- "tab": "1612772287426",
- "name": "errors from MQTT Broker",
- "x": 594,
- "y": 57,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#DA4453",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615563373927",
- "component": "debug",
- "tab": "1615551125555",
- "name": "Debug",
- "x": 755,
- "y": 155,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#DA4453",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615566865233",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "tb-push",
- "x": 755,
- "y": 248,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1615798582262",
- "component": "debug",
- "tab": "1615551125555",
- "name": "CMD_debug",
- "x": 755,
- "y": 346,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615802995322",
- "component": "debug",
- "tab": "1611921777196",
- "name": "Debug",
- "x": 596.8833312988281,
- "y": 566.3500061035156,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Disabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": false
- }
- },
- {
- "id": "1615809128443",
- "component": "debug",
- "tab": "1611921777196",
- "name": "tempToTb",
- "x": 595.8833312988281,
- "y": 658.3500061035156,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1615809595184",
- "component": "virtualwireout",
- "tab": "1611921777196",
- "name": "tb-push",
- "x": 597.8833312988281,
- "y": 377.25,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1616165795916",
- "component": "httproute",
- "tab": "1615551125555",
- "name": "POST /terminal",
- "x": 135,
- "y": 547,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1684060205000"
- },
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Listening",
- "color": "green"
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /terminal__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __false__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
- "options": {
- "timeout": 10,
- "cachepolicy": 0,
- "cacheexpire": "5 minutes",
- "size": 5,
- "url": "/terminal",
- "method": "POST",
- "name": "",
- "flags": [
- 10000,
- "id:1616165795916",
- "post"
- ],
- "emptyresponse": false
- }
- },
- {
- "id": "1616165824813",
- "component": "httpresponse",
- "tab": "1615551125555",
- "name": "HTTP Response",
- "x": 753,
- "y": 423,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5D9CEC",
- "notes": "",
- "options": {
- "datatype": "json"
- }
- },
- {
- "id": "1617104731852",
- "component": "debug",
- "tab": "1615551125555",
- "name": "DIDO_Debug",
- "x": 669,
- "y": 1040,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1617114651703",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOff line",
- "x": 133,
- "y": 1161,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "{line: 1, command: \"off\", force: true}",
- "datatype": "object"
- }
- },
- {
- "id": "1617115013095",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "tb-push",
- "x": 669,
- "y": 1150,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1617284749681",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "update profile / node",
- "x": 112,
- "y": 208,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "datatype": "string",
- "data": "profile_nodes"
- }
- },
- {
- "id": "1618235171399",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "tun tasks",
- "x": 184,
- "y": 279,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "run"
- }
- },
- {
- "id": "1618300858252",
- "component": "debug",
- "tab": "1612772287426",
- "name": "wsmqtt-exit1",
- "x": 597.8833312988281,
- "y": 149,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1618393583970",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "to-cmd-manager",
- "x": 668.8833312988281,
- "y": 1269,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "from-dido-controller",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "from-dido-controller"
- }
- },
- {
- "id": "1618393674428",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "platform-rpc-call",
- "x": 132.88333129882812,
- "y": 367,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "platform-rpc-call",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "platform-rpc-call"
- }
- },
- {
- "id": "1618393759854",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "cmd_to_dido",
- "x": 119.88333129882812,
- "y": 1007,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1683664161036"
- },
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "cmd_to_dido",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "cmd_to_dido"
- }
- },
- {
- "id": "1618393827655",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "cmd_to_dido",
- "x": 752.8833312988281,
- "y": 527,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "cmd_to_dido",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "cmd_to_dido"
- }
- },
- {
- "id": "1618558465485",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "platform-rpc-call",
- "x": 597.8833312988281,
- "y": 247,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "platform-rpc-call",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "platform-rpc-call"
- }
- },
- {
- "id": "1618572059773",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOn line",
- "x": 132,
- "y": 1085,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "datatype": "object",
- "data": "{line: 1, command: \"on\", force: true}"
- }
- },
- {
- "id": "1619515097737",
- "component": "cmd_manager",
- "tab": "1615551125555",
- "name": "CMD Manager",
- "x": 452.1091003417969,
- "y": 341.05455017089844,
- "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"
- }
- ],
- "4": [
- {
- "index": "0",
- "id": "1635936391935"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5D9CEC",
- "notes": "",
- "options": {}
- },
- {
- "id": "1619605019281",
- "component": "httproute",
- "tab": "1615551125555",
- "name": "GET db",
- "x": 173,
- "y": 653,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1684060205000"
- },
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Listening",
- "color": "green"
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __GET /db__\n- flags: undefined\n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
- "options": {
- "timeout": 5,
- "cachepolicy": 0,
- "cacheexpire": "5 minutes",
- "size": 5,
- "url": "/db",
- "method": "GET",
- "name": "",
- "flags": [
- 5000,
- "id:1619605019281",
- "get"
- ]
- }
- },
- {
- "id": "1619784672383",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOnAlarm",
- "x": 117,
- "y": 1242,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "{command: \"turnOnAlarm\"}",
- "datatype": "object"
- }
- },
- {
- "id": "1619784812964",
- "component": "trigger",
- "tab": "1615551125555",
- "name": "turnOffAlarm",
- "x": 118,
- "y": 1307,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "data": "{command: \"turnOffAlarm\"}",
- "datatype": "object"
- }
- },
- {
- "id": "1621340721628",
- "component": "virtualwireout",
- "tab": "1611921777196",
- "name": "modbus_to_dido",
- "x": 599,
- "y": 471,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "modbus_to_dido",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "modbus_to_dido"
- }
- },
- {
- "id": "1622640022885",
- "component": "httproute",
- "tab": "1615551125555",
- "name": "POST /db_connector",
- "x": 98,
- "y": 1586,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1622640073521"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Listening",
- "color": "green"
- },
- "color": "#5D9CEC",
- "notes": "### Configuration\n\n- __POST /db_connector__\n- flags: \n- maximum request data length: __5 kB__\n- empty response: __undefined__\n- cache policy: __no cache__\n- cache expire: __5 minutes__",
- "cloning": false,
- "options": {
- "timeout": 5,
- "cachepolicy": 0,
- "cacheexpire": "5 minutes",
- "size": 5,
- "url": "/db_connector",
- "method": "POST",
- "flags": [
- 5000,
- "id:1622640022885",
- "post"
- ]
- }
- },
- {
- "id": "1622640073521",
- "component": "db_connector",
- "tab": "1615551125555",
- "name": "DbConnector",
- "x": 372,
- "y": 1572,
- "connections": {
- "1": [
- {
- "index": "0",
- "id": "1622641420685"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#2134B0",
- "notes": "",
- "options": {
- "edge": "undefined"
- }
- },
- {
- "id": "1622641420685",
- "component": "httpresponse",
- "tab": "1615551125555",
- "name": "HTTP Response",
- "x": 596,
- "y": 1586,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5D9CEC",
- "notes": "",
- "options": {}
- },
- {
- "id": "1634303504177",
- "component": "monitormemory",
- "tab": "1612772287426",
- "name": "RAM",
- "x": 69.88333129882812,
- "y": 888.5,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634465281992"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "704.30 MB / 982.12 MB",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "enabled": true,
- "interval": 30000
- }
- },
- {
- "id": "1634303533779",
- "component": "monitordisk",
- "tab": "1612772287426",
- "name": "disk",
- "x": 70.88333129882812,
- "y": 982.5,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634465821120"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "5.45 GB / 6.86 GB",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "enabled": true,
- "path": "/",
- "interval": 30000
- }
- },
- {
- "id": "1634303595494",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "send-to-services",
- "x": 51.883331298828125,
- "y": 1400.5,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634463186563"
- },
- {
- "index": "1",
- "id": "1634488120710"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1634303602169",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "send-to-services",
- "x": 426.8833312988281,
- "y": 878.5,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1634303685503",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "send-to-services",
- "x": 600.8833312988281,
- "y": 341.5,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1634303743260",
- "component": "httprequest",
- "tab": "1612772287426",
- "name": "192.168.252.2:8004/sentmessage",
- "reference": "",
- "x": 506.8833312988281,
- "y": 1331.7333374023438,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1635327431236"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5D9CEC",
- "notes": "",
- "options": {
- "stringify": "json",
- "method": "POST",
- "url": "http://192.168.252.2:8004/sentmessage"
- }
- },
- {
- "id": "1634463186563",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 305.75,
- "y": 1442,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1634464580289",
- "component": "code",
- "tab": "1612772287426",
- "name": "Code",
- "x": 245,
- "y": 787,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634465243324"
- },
- {
- "index": "0",
- "id": "1634303602169"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#656D78",
- "notes": "",
- "options": {
- "keepmessage": true,
- "code": "let response = {};\nresponse.cpu = value.cpu;\nresponse.uptime = value.uptime;\n\nsend(0, response);",
- "outputs": 1
- }
- },
- {
- "id": "1634465243324",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 428,
- "y": 784,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1634465281992",
- "component": "code",
- "tab": "1612772287426",
- "name": "Code",
- "x": 245,
- "y": 884,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634465338103"
- },
- {
- "index": "0",
- "id": "1634303602169"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#656D78",
- "notes": "",
- "options": {
- "keepmessage": true,
- "code": "value.sender = \"ram\";\n\nlet response = {};\n\nresponse.memory_total = Math.round(value.total / (1024 ** 2));\nresponse.memory_free = Math.round(value.free / (1024 ** 2));\nresponse.memory_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
- "outputs": 1
- }
- },
- {
- "id": "1634465338103",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 429,
- "y": 976,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1634465821120",
- "component": "code",
- "tab": "1612772287426",
- "name": "Code",
- "x": 245,
- "y": 978,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634465892500"
- },
- {
- "index": "0",
- "id": "1634303602169"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#656D78",
- "notes": "",
- "options": {
- "keepmessage": true,
- "code": "value.sender = \"hdd\";\n\nlet response = {};\n\nresponse.hdd_total = Math.round(value.total / (1024 ** 2));\nresponse.hdd_free = Math.round(value.free / (1024 ** 2));\nresponse.hdd_used = Math.round(value.used / (1024 ** 2));\n\nsend(0, response);",
- "outputs": 1
- }
- },
- {
- "id": "1634465892500",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 432,
- "y": 1068,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1634484067516",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Send info",
- "x": 513,
- "y": 1441,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1634488120710",
- "component": "infosender",
- "tab": "1612772287426",
- "name": "Info sender",
- "x": 301,
- "y": 1336,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634484067516"
- },
- {
- "index": "0",
- "id": "1634303743260"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#2134B0",
- "notes": "",
- "options": {
- "edge": "undefined"
- }
- },
- {
- "id": "1635327431236",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 837.8833312988281,
- "y": 1325.5,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1635936391935",
- "component": "virtualwireout",
- "tab": "1615551125555",
- "name": "send-to-services",
- "x": 753,
- "y": 623,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1637069803394",
- "component": "monitorconsumption",
- "tab": "1612772287426",
- "name": "CPU",
- "x": 69,
- "y": 791,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634464580289"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "3.6% / 111.50 MB",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "monitorfiles": true,
- "monitorconnections": true,
- "monitorsize": true,
- "monitorconsumption": true,
- "enabled": true,
- "interval": 30000
- }
- },
- {
- "id": "1683664161036",
- "component": "debug",
- "tab": "1615551125555",
- "name": "CMDtoDIDO",
- "x": 392,
- "y": 1012,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1683981346282",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "from-dido-controller",
- "x": 112,
- "y": 459,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1684055037116"
- },
- {
- "index": "1",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "from-dido-controller",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "from-dido-controller"
- }
- },
- {
- "id": "1684055037116",
- "component": "debug",
- "tab": "1615551125555",
- "name": "from dido to cmd",
- "x": 451,
- "y": 532,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1684060205000",
- "component": "debug",
- "tab": "1615551125555",
- "name": "HTTP routes",
- "x": 450,
- "y": 639,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1684179110403",
- "component": "debug",
- "tab": "1611921777196",
- "name": "MDBToDido",
- "x": 598,
- "y": 147,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1699963668903",
- "component": "dido_controller",
- "tab": "1615551125555",
- "name": "DIDO_Controller",
- "x": 397,
- "y": 1131,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1617104731852"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1617104731852"
- },
- {
- "index": "0",
- "id": "1617115013095"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1618393583970"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#2134B0",
- "notes": "",
- "options": {
- "edge": "undefined"
- }
- },
- {
- "id": "1699964678894",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "modbus_to_dido",
- "x": 96,
- "y": 924,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1699963668903"
- },
- {
- "index": "0",
- "id": "1699964793925"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "modbus_to_dido",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "modbus_to_dido"
- }
- },
- {
- "id": "1699964793925",
- "component": "debug",
- "tab": "1615551125555",
- "name": "modbusToDido",
- "x": 388,
- "y": 920,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1699965957410",
- "component": "modbus_reader",
- "tab": "1611921777196",
- "name": "Modbus reader",
- "x": 232,
- "y": 175,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1611951142547"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1621340721628"
- },
- {
- "index": "0",
- "id": "1684179110403"
- },
- {
- "index": "0",
- "id": "1717441414646"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1615809595184"
- },
- {
- "index": "0",
- "id": "1714752862828"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#2134B0",
- "notes": "",
- "options": {}
- },
- {
- "id": "1700411878636",
- "component": "thermometer",
- "tab": "1611921777196",
- "name": "Thermometer",
- "x": 234.75,
- "y": 444,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1615802995322"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1615809595184"
- },
- {
- "index": "0",
- "id": "1615809128443"
- }
- ],
- "2": [
- {
- "index": "0",
- "id": "1621340721628"
- },
- {
- "index": "0",
- "id": "1732889185927"
- },
- {
- "index": "0",
- "id": "1717441414646"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5CB36D",
- "notes": "",
- "options": {}
- },
- {
- "id": "1714752862828",
- "component": "debug",
- "tab": "1611921777196",
- "name": "MDBToTb",
- "x": 766,
- "y": 324,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1717441414646",
- "component": "code",
- "tab": "1611921777196",
- "name": "device-status",
- "x": 764.0833282470703,
- "y": 222,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1717442627834"
- },
- {
- "index": "0",
- "id": "1717442631338"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#656D78",
- "notes": "",
- "options": {
- "keepmessage": true,
- "code": "if(value.hasOwnProperty(\"status\"))\n{\n\tif(value.status.includes(\"-em\"))\n\t{\n\t\tsend(0, {\"em_status\": \"NOK\"});\n\t}\n\telse if(value.status.includes(\"twilight\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"NOK\"});\n\t}\n\telse if(value.status === \"NOK-thermometer\")\n\t{\n\t\tsend(0, {\"thermometer\": \"NOK\"});\n\t}\n}\n\nif(value.hasOwnProperty(\"values\"))\n{\n\tif(value.values.hasOwnProperty(\"twilight_sensor\"))\n\t{\n\t\tsend(0, {\"lux_sensor\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"Phase_1_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_voltage\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Total_power\") ||\n\t\t\tvalue.values.hasOwnProperty(\"Phase_1_current\"))\n\t{\n\t\tsend(0, {\"em_status\": \"OK\"});\n\t}\n\telse if(value.values.hasOwnProperty(\"temperature\"))\n\t{\n\t\tsend(0, {\"thermometer\": \"OK\"});\n\t}\n}",
- "outputs": 1
- }
- },
- {
- "id": "1717442627834",
- "component": "debug",
- "tab": "1611921777196",
- "name": "modbus service",
- "x": 966.0833282470703,
- "y": 165,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1717442631338",
- "component": "virtualwireout",
- "tab": "1611921777196",
- "name": "send-to-services",
- "x": 968.0833282470703,
- "y": 268,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1718016045116",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "tb-push",
- "x": 77.75,
- "y": 1630,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016052341"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1718016052341",
- "component": "slack_filter",
- "tab": "1612772287426",
- "name": "Slack Filter",
- "x": 296,
- "y": 1671,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016086212"
- },
- {
- "index": "0",
- "id": "1718016073501"
- }
- ]
- },
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Running",
- "color": "gray"
- },
- "color": "#30E193",
- "notes": "",
- "options": {
- "slack_channel": "C071KN2Q8SK",
- "tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
- "message_includes": "[\"is responding again\", \"Flow has been restarted\", \"Node db has changed\"]",
- "types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
- "name": "test_rvo_debian12"
- }
- },
- {
- "id": "1718016073501",
- "component": "httprequest",
- "tab": "1612772287426",
- "name": "http://192.168.252.2:8004/slack",
- "x": 495,
- "y": 1753,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016086212"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#5D9CEC",
- "notes": "",
- "options": {
- "stringify": "json",
- "method": "POST",
- "url": "http://192.168.252.2:8004/slack"
- }
- },
- {
- "id": "1718016086212",
- "component": "debug",
- "tab": "1612772287426",
- "name": "Debug",
- "x": 832,
- "y": 1664,
- "connections": {},
- "disabledio": {
- "input": [
- 0
- ],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1718016094070",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "Trigger",
- "x": 79,
- "y": 1723,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1718016052341"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {
- "datatype": "object",
- "data": "{ \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\": [ { \"ts\": 1716289039281, \"values\": { \"_event\": { \"type\": \"alert\", \"status\": \"new\", \"source\": { \"func\": \"CMD Manager: process cmd\", \"component\": \"1619515097737\", \"component_name\": \"CMD Manager\", \"edge\": \"g9OxBZ5KRwNznlY6pAppqEAWXvjdEL4eGQobMDy2\" }, \"message\": \"NOW CONNECTED TO SLACK !\", \"message_data\": \"\" } } } ] }"
- }
- },
- {
- "id": "1731068658334",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 79.75,
- "y": 164,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1612776786008"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069001548",
- "component": "db_init",
- "tab": "1612772287426",
- "name": "DB Initialization",
- "x": 1003.75,
- "y": 240.25,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069033416"
- }
- ],
- "1": [
- {
- "index": "0",
- "id": "1747561603739"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069033416",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 1244.75,
- "y": 233.25,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069059135",
- "component": "showdb",
- "tab": "1612772287426",
- "name": "Show db data",
- "x": 1121.75,
- "y": 814.25,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069079243"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069079243",
- "component": "debug",
- "tab": "1612772287426",
- "name": "dbData",
- "x": 1324.75,
- "y": 863.25,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1731069116691",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "settings",
- "x": 867.75,
- "y": 667.75,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069131637",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "relaysData",
- "x": 798.75,
- "y": 733.75,
- "connections": {
- "0": [
- {
- "index": "1",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069137374",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "nodesData",
- "x": 762.75,
- "y": 801.75,
- "connections": {
- "0": [
- {
- "index": "2",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069179846",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "pinsData",
- "x": 782.75,
- "y": 867.75,
- "connections": {
- "0": [
- {
- "index": "3",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069192937",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "sample data",
- "x": 801.75,
- "y": 933.75,
- "connections": {
- "0": [
- {
- "index": "4",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731069264443",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 63.75,
- "y": 1279,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1634488120710"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069334626",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "db-init",
- "x": 172.88333129882812,
- "y": 129,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1619515097737"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069548145",
- "component": "virtualwirein",
- "tab": "1611921777196",
- "name": "db-init",
- "x": 46.75,
- "y": 192,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1699965957410"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731069567152",
- "component": "virtualwirein",
- "tab": "1611921777196",
- "name": "db-init",
- "x": 44.75,
- "y": 465,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1700411878636"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731070156936",
- "component": "virtualwirein",
- "tab": "1615551125555",
- "name": "db-init",
- "x": 126.88333129882812,
- "y": 1377,
- "connections": {
- "0": [
- {
- "index": "2",
- "id": "1699963668903"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1731234189516",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "monitor.txt",
- "x": 821.75,
- "y": 1000.75,
- "connections": {
- "0": [
- {
- "index": "5",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1731234189551",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "err.txt",
- "x": 862.75,
- "y": 1064.75,
- "connections": {
- "0": [
- {
- "index": "6",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- },
- {
- "id": "1732700042559",
- "component": "nodesdb_change_check",
- "tab": "1612772287426",
- "name": "Nodes DB change check",
- "x": 263.8833312988281,
- "y": 1993.2333984375,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1732700071298"
- },
- {
- "index": "0",
- "id": "1732700642917"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#888600",
- "notes": "",
- "options": {}
- },
- {
- "id": "1732700057052",
- "component": "virtualwirein",
- "tab": "1612772287426",
- "name": "db-init",
- "x": 84.75,
- "y": 1994,
- "connections": {
- "0": [
- {
- "index": "0",
- "id": "1732700042559"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "db-init",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "db-init"
- }
- },
- {
- "id": "1732700071298",
- "component": "debug",
- "tab": "1612772287426",
- "name": "nodesChange",
- "x": 561.8833312988281,
- "y": 2055.2333984375,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1732700642917",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "tb-push",
- "x": 557.8833312988281,
- "y": 1949,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "tb-push",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "tb-push"
- }
- },
- {
- "id": "1732889185927",
- "component": "debug",
- "tab": "1611921777196",
- "name": "tempToDido",
- "x": 594.8833312988281,
- "y": 753,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "Enabled",
- "color": "gray"
- },
- "color": "#967ADC",
- "notes": "",
- "options": {
- "type": "data",
- "repository": false,
- "enabled": true
- }
- },
- {
- "id": "1747561603739",
- "component": "virtualwireout",
- "tab": "1612772287426",
- "name": "send-to-services",
- "x": 1243.8833312988281,
- "y": 334.5,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "send-to-services",
- "color": "gray"
- },
- "color": "#303E4D",
- "notes": "",
- "options": {
- "wirename": "send-to-services"
- }
- },
- {
- "id": "1747562867845",
- "component": "comment",
- "tab": "1612772287426",
- "name": "FLOW STARTING POINT",
- "x": 1003.5666656494141,
- "y": 178,
- "connections": {},
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#704cff",
- "notes": "",
- "options": {}
- },
- {
- "id": "1750771612786",
- "component": "trigger",
- "tab": "1612772287426",
- "name": "devices",
- "x": 896.75,
- "y": 1122.75,
- "connections": {
- "0": [
- {
- "index": "7",
- "id": "1731069059135"
- }
- ]
- },
- "disabledio": {
- "input": [],
- "output": []
- },
- "state": {
- "text": "",
- "color": "gray"
- },
- "color": "#F6BB42",
- "notes": "",
- "options": {}
- }
- ],
- "version": 624
-}
\ No newline at end of file
diff --git a/flow/dido_controller.js b/flow/dido_controller.js
index 8843fe0..b429b14 100644
--- a/flow/dido_controller.js
+++ b/flow/dido_controller.js
@@ -4,8 +4,9 @@ exports.version = '2.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
exports.input = 3;
-exports.output = ["red", "white", "yellow", "green"];
+exports.output = ["red", "white", "yellow"];
exports.click = false;
+exports.author = 'Daniel Segeš';
exports.icon = 'bolt';
exports.options = { edge: "undefined" };
@@ -34,42 +35,46 @@ 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
-
-state_of_main_switch - reportovat stav hlaveho istica : 0-> off 1-> on
-rotary_switch_state - sem by sa mal reportovat stav vstupov manual a auto pola nasledovnej logiky: Manual = 1 a Auto = 0 -> Manu
-Manual = 0 a Auto = 0 -> Off, Manual = 0 a Auto = 1 -> Automatic
-
-door_condition - pin 6, dverový kontakt -> 1 -> vyreportuje Closed, 0 -> vyreportuje Ope
-twilight_sensor - hodnotu, ktoru vracia ten analogovy vstup (17) treba poslat sem ako float number. Zrejme tu potom pridame nejaky koeficient prevodu na luxy
-
-Na kazdu liniu
-state_of_breaker - podla indexu istica sa reportuje jeho stav, teda istic na liniu 1: 0-> off, 1-> on
-state_of_contactor - podla indexu stkaca sa reportuje jeho stav, teda stykac 1 na liniu 1: 0-> off, 1-> on
*/
-const { errLogger, logger, monitor } = require('./helper/logger');
-const SerialPort = require('serialport');
-const WebSocket = require('ws');
-const { runSyncExec } = require('./helper/serialport_helper');
-const { bytesToInt, resizeArray } = require('./helper/utils');
-const { sendNotification } = require('./helper/notification_reporter');
-const bitwise = require('bitwise');
-const DataToTbHandler = require('./helper/DataToTbHandler');
-let tbHandler;
+/*
+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
-const errorHandler = require('./helper/ErrorToServiceHandler');
+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
-let ws = null;
-let rsPort = null;
+zjavne nám v jsone chýba stav hlavného ističa. Musíme to potom doplniť
-let pinsData;
-let relaysData;
-let rvoTbName;
-let GLOBALS; //FLOW global GLOBALS
-let SETTINGS; // GLOBALS.settings
-let controller_type;
-let hasMainSwitch;
+Na každú líniu:
+state_of_breaker - podľa indexu ističa sa reportuje jeho stav, teda istič 1 na líniu 1: 0-> off 1-> on
+state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda stykač 1 na líniu 1: 0-> off 1-> on
+ momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale tá zmena by sa mala ukázať aj na platforme
+*/
+
+
+//globals
+//FIRMWARE version
+FLOW.OMS_edge_fw_version = "2024-07-08";//rok-mesiac-den
+FLOW.OMS_edgeName = "";
+FLOW.OMS_maintenance_mode = false;
+
+//dynamic values
+FLOW.OMS_masterNodeIsResponding = true; //cmd_manager
+//FLOW.OMS_brokerready = false //wsmqttpublish
+FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer
+
+//see loadSettings() in cmd_manager
+FLOW.OMS_language = "en";//cmd_manager
+FLOW.OMS_rvo_name = "";//cmd_manager
+FLOW.OMS_rvo_tbname = "";//relaysData
+FLOW.OMS_temperature_adress = "";//cmd_manager
+//-----------------------------------------------
let alarmStatus = "OFF";
@@ -79,31 +84,69 @@ const SEND_TO = {
cmd_manager: 2
}
+var log4js = require("log4js");
+var path = require('path');
+
+log4js.configure({
+ appenders: {
+ errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
+ monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
+ console: { type: 'console' }
+ },
+ categories: {
+ errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
+ monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
+ //another: { appenders: ['console'], level: 'trace' },
+ default: { appenders: ['console'], level: 'trace' }
+ }
+});
+
+const errLogger = log4js.getLogger("errLogs");
+const logger = log4js.getLogger();
+const monitor = log4js.getLogger("monitorLogs");
+
+//console.log(path.join(__dirname, 'err.txt', "-----------------------------"));
+
+/*
+process.on('uncaughtException', function (err) {
+
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
+
+ //process.exit(1);
+})
+*/
+
+//USAGE
+//logger.debug("text")
+//monitor.info('info');
+//errLogger.error("some error");
exports.install = function(instance) {
- process.on('uncaughtException', function(err) {
+ process.on('uncaughtException', function (err) {
//TODO send to service
-
+
errLogger.error('uncaughtException:', err.message)
errLogger.error(err.stack);
errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
-
+
//process.exit(1);
})
- let previousValues = {};
+ let previousValues = {temperature: 0};
let rsPortReceivedData = [];
- //to be able to get proper twilight values
let twilight_sensor_interval = 5;//minutes
let twilight_sensor = [];
const twilight_sensor_array = [];
let twilightError = false;
- monitor.info("DIDO_Relay_Controller installed");
+ let edgeName = "";
+
+ monitor.info("DI_DO_Relay_Controller installed");
//key is PIN number , line: 0 = RVO
/*
@@ -123,191 +166,240 @@ exports.install = function(instance) {
"16": {tbname: "", type: "twilight_sensor", "line": 0}, // twilight_sensor = pin16
};
*/
+
+ const dbPins = TABLE("pins");
+ let pinsData = {};//key is pin
- //status for calculating Statecodes-we make it global to see it from outside
- FLOW.deviceStatus = { //key is device name: temperature,....
- "state_of_main_switch": "Off", //Hlavny istic (alebo druhy dverovy kontakt)
- "rotary_switch_state": "Off", //Prevadzkovy
- "door_condition": "closed", //Dverový kontakt
- "em": "OK", //elektromer rvo
- "temperature": "OK", //templomer
- "battery": "OK", //Bateria
- "power_supply": "OK", //Zdroj
- "master_node": "OK", //MN - GLOBALS.settings.masterNodeIsResponding
- "no_voltage": "OK", //GLOBALS.settings.no_voltage - vypadok napatia na faze
- "state_of_breaker": {}, //"Off",//Istic
- "state_of_contactor": {}, //"Off",//Stykac
- "twilight_sensor": "OK" //lux sensor
- };
- let deviceStatus = FLOW.deviceStatus;
+ const dbRelays = TABLE("relays");
+ let relaysData = {};//key is line
+ //status for calculating Statecodes
+ let deviceStatuses = {};//key is device name: temperature,....
+ deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič
+ deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód
+ deviceStatuses["door_condition"] = "closed";//Dverový kontakt
+ deviceStatuses["em"] = "OK";//elektromer rvo
+ deviceStatuses["temperature"] = "OK";//templomer
+ deviceStatuses["battery"] = "OK";//Batéria
+ deviceStatuses["power_supply"] = "OK";//Zdroj
+ deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding
+ deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze
- function main() {
+ deviceStatuses["state_of_breaker"] = {};//"Off";//Istič
+ deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač
+ deviceStatuses["twilight_sensor"] = "OK"; //lux sensor
- GLOBALS = FLOW.GLOBALS;
- SETTINGS = FLOW.GLOBALS.settings;
- rvoTbName = SETTINGS.rvoTbName;
- pinsData = GLOBALS.pinsData;
- relaysData = GLOBALS.relaysData;
+ /*
+ dbRelays.on('change', function(doc, old) {
+ console.log("'DI_DO_Controller - dbRelays.on('change'");
+ instance.send(SEND_TO.cmd_manager, "reload_relays");
+ });
+ */
- tbHandler = new DataToTbHandler(SEND_TO.tb);
- tbHandler.setSender(exports.title);
+ const SerialPort = require('serialport');
+ const WebSocket = require('ws');
- controller_type = SETTINGS.controller_type; //"lm" or "unipi"
- hasMainSwitch = SETTINGS.has_main_switch;
+ let ws = null;
+ let rsPort = null;
+
+ //const { exec } = require('child_process');
+ const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js');
+ const { bytesToInt, resizeArray } = require('./helper/utils');
+ const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
+ const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js');
+ const bitwise = require('bitwise');
- if (controller_type == "") controller_type = "lm";
+ const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
+ const errorHandler = new ErrorToServiceHandler();
- console.log(exports.title, "controller type: ", controller_type);
+ //let useTurnOffCounter = false;
+ //let turnOffCounter = 0;
+ let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine
+ if(controller_type == "") controller_type = "lm";
- if (controller_type === "lm") {
+ console.log(exports.title, "controller type: ", controller_type);
+
+ async function loadAllDb()
+ {
+ let responsePins = await promisifyBuilder(dbPins.find());
+ pinsData = makeMapFromDbResult(responsePins, "pin");
+
+ let responseRelays = await promisifyBuilder(dbRelays.find());
+ relaysData = makeMapFromDbResult(responseRelays, "line");
+
+ FLOW.OMS_rvo_tbname = relaysData[0].tbname;
+
+ if(controller_type === "lm")
+ {
handleRsPort();
}
- else if (controller_type === "unipi") {
+ else if(controller_type === "unipi")
+ {
handleWebSocket();
}
else {
errLogger.debug("UNKNOWN controller_type:", controller_type);
}
- }
+ }
- function initialSetting() {
- //force turn off relays
-
+ function initialSetting()
+ {
+ //force turn off relays & set tbname
let keys = Object.keys(pinsData);
- for (let i = 0; i < keys.length; i++) {
+ for(let i = 0; i < keys.length; i++)
+ {
let key = keys[i];
- let line = pinsData[key].line;
+ let line = pinsData[key].line;
- if (line != undefined) {
- if (relaysData[line] != undefined) {
+ if(line != undefined)
+ {
+ if(relaysData[line] != undefined)
+ {
pinsData[key].tbname = relaysData[line].tbname;
- //relaysData[line].contactor = 0;
+
+ relaysData[line].contactor = 0;
}
- else {
+ else
+ {
errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line);
- sendNotification("set port ", rvoTbName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance);
+
+ //sendNotification("set port ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null );
+ sendNotification("set port ", edgeName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance );
}
}
- if (pinsData[key].type == "state_of_contactor") {
+ if(pinsData[key].type == "state_of_contactor")
+ {
let pin = key - 1;
- if (controller_type === "unipi") pin = key;
+ if(controller_type === "unipi") pin = key;
+
+ //this will modify database
+ let forceTurnOff = true;
+ turnOffLine(line, pin, forceTurnOff, "turn off on startup");
}
}
//report RVO version relaysData[0].tbname;
let values = {};
- values["edge_fw_version"] = SETTINGS.edge_fw_version;
- values["maintenance_mode"] = SETTINGS.maintenance_mode;
+ values["edge_fw_version"] = FLOW.OMS_edge_fw_version;
+ values["maintenance_mode"] = FLOW.OMS_maintenance_mode;
+ values["status"] = "OK";
- sendTelemetry(values, rvoTbName);
+ edgeName = relaysData[0].tbname;
+ FLOW.OMS_edgeName = edgeName;
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "buildTasks" });
+ dataToTb = {
+ [edgeName]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
- sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
- monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
+ instance.send(SEND_TO.tb, dataToTb);
+
+ let time = 3*1000;
+ setTimeout(function(){
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"});
+
+ sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", SEND_TO.tb, instance );
+ monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_edge_fw_version);
+
+ }, time);
}
- function handleRsPort() {
-
- if (rsPort) {
- rsPort.removeAllListeners();
- rsPort = null;
- }
-
+ function handleRsPort()
+ {
//TODO build according to pins!!!
//! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0")
- const setRSPortData = [0xAA, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 1, 1, 1, 1, 0, 0, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0];
+ const setRSPortData = [0xAA,6,6,6,6,6,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,10,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,15,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0];
rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false });
- rsPort.on('open', async function() {
+ rsPort.on('error', function(err) {
+ logger.debug("rsPort opened error - failed", err.message);
+ instance.send(SEND_TO.debug, err.message);
- 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) {
+ errorHandler.sendMessageToService( exports.title + " rsPort opened error - failed: " + err.message);
+ })
+
+ rsPort.on('open', async function() {
+
+ await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) {
//set port
rsPort.write(Buffer.from(setRSPortData), function(err) {
- if (!err) {
- monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
+ monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
- turnAlarm("off");
- initialSetting();
- }
+ turnOffAlarm();
+
+ //useTurnOffCounter = true;
+ //turnOffCounter = relaysData.length - 1;
+
+ initialSetting();
})
- }).catch(function(reason) {
- errLogger.error(exports.title + " runSyncExec - promise rejected:" + reason);
- errorHandler.sendMessageToService(exports.title + " runSyncExec - promise rejected:" + reason);
- });
+ }).catch(function (reason) {
+ //instance.send(SEND_TO.debug, exports.title + " runSyncExec - promise rejected:" + reason);
+ errLogger.error( exports.title + " runSyncExec - promise rejected:" + reason);
+ errorHandler.sendMessageToService( exports.title + " runSyncExec - promise rejected:" + reason);
+ });
+
});
-
- rsPort.on('data', function(data) {
-
+
+ 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 (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);
+ 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', err => {
- let message = "Dido: rsPort error: " + err.message;
- logger.debug(message);
- monitor.info(message);
- errorHandler.sendMessageToService(message);
- })
-
+
rsPort.on("close", () => {
- let message = "Dido: rsPort closed - reconnecting ...";
- logger.debug(message);
- monitor.info(message);
- setTimeout(handleRsPort, 1000);
+ rsPort.close();
})
rsPort.open();
+
}
function handleWebSocket() {
- if (ws) {
- ws.removeAllListeners();
- ws = null;
- }
-
//to keep websocket opened, we send request every 150 seconds
let startRequests = null;
@@ -315,134 +407,212 @@ exports.install = function(instance) {
ws = new WebSocket('ws:/0.0.0.0:1234/ws');
ws.onopen = function open() {
-
+
instance.send(0, exports.title + " running");
- turnAlarm("off");
+ turnOffAlarm();
+ // useTurnOffCounter = true;
+ // turnOffCounter = relaysData.length - 1;
initialSetting();
+ ws.send(JSON.stringify({"cmd":"all"}));
- setTimeout(function() { ws.send(JSON.stringify({ cmd: "all" })) }, 5000);
// 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(() => {
- ws.send(JSON.stringify({ "cmd": "filter", "dev": ["neuron"] }));
+ // console.log(" *** data from evok requested");
+ ws.send(JSON.stringify({"cmd":"filter", "dev": ["neuron"]}));
}, 150000)
};
-
-
- // SAMPLE DATA FROM WEBSOCKET
- // {
- // glob_dev_id: 1,
- // modes: [ 'Simple' ],
- // value: 0,
- // circuit: '1_07',
- // pending: false,
- // relay_type: 'physical',
- // dev: 'relay',
- // mode: 'Simple'
- // },
- // {
- // counter_modes: [ 'Enabled', 'Disabled' ],
- // glob_dev_id: 1,
- // modes: [ 'Simple', 'DirectSwitch' ],
- // value: 0,
- // circuit: '1_08',
- // debounce: 50,
- // counter: 0,
- // counter_mode: 'Enabled',
- // dev: 'input',
- // mode: 'Simple'
- // },
- ws.onmessage = async function(data) {
+
+// SAMPLE DATA FROM WEBSOCKET
+// {
+// glob_dev_id: 1,
+// modes: [ 'Simple' ],
+// value: 0,
+// circuit: '1_07',
+// pending: false,
+// relay_type: 'physical',
+// dev: 'relay',
+// mode: 'Simple'
+// },
+// {
+// counter_modes: [ 'Enabled', 'Disabled' ],
+// glob_dev_id: 1,
+// modes: [ 'Simple', 'DirectSwitch' ],
+// value: 0,
+// circuit: '1_08',
+// debounce: 50,
+// counter: 0,
+// counter_mode: 'Enabled',
+// dev: 'input',
+// mode: 'Simple'
+// },
+ ws.onmessage = function(data) {
data = JSON.parse(data.data);
// data comes in array except of "temperature" ==> it comes as an object
- // we do not handle temperature from evok any more => we return, if temperature comes:
- if (isObject(data)) return;
+ if(!Array.isArray(data))
+ {
+ let value = data['value'];
+
+ // temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB
+ if(Math.abs(previousValues["temperature"] - value) > 0.21 )
+ {
+ const dataToTb = {
+ [FLOW.OMS_rvo_tbname]: [
+ {
+ "ts": Date.now(),
+ "values": {temperature: value}
+ }
+ ]
+ };
+
+ deviceStatuses["temperature"] = "OK";
+ previousValues["temperature"] = value;
+ instance.send(SEND_TO.tb, dataToTb);
+ }
+ return;
+ }
data.map(item => {
-
+
let value = item['value'];
- let pin = item["dev"] + item["circuit"]; // for example "ro1_03" or "di1_01"
+ let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01"
- if (pin == undefined) return;
+ if (pin == undefined) return;
switchLogic(pin, value);
})
}
+
- ws.on('error', err => {
- logger.debug('Dido: websocket error', err);
+ ws.on('error', (err) => {
+ monitor.info('websocket error, reconnect')
+ instance.send(SEND_TO.debug, err.message);
+ clearInterval(startRequests);
+ ws = null;
+ setTimeout(handleWebSocket, 1000);
})
- ws.onclose = function() {
- logger.debug('Dido: websocket onclose, reconnecting...')
+
+ ws.onclose = function(){
+ // connection closed, discard old websocket and create a new one in 5s
+ // stopRequests();
+ monitor.info('websocket onclose, reconnect')
clearInterval(startRequests);
+ ws = null;
+ console.log("ws is null now, reconnecting...");
setTimeout(handleWebSocket, 1000);
}
}
+ // ! do we need requests every minute ???
+ // const startRequests = () => {
+ // console.log("startRequest function called");
+ // start = setInterval(() => {
+ // // console.log("data from evok requested");
+ // ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"}));
+ // // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]}));
+ // }, 150000)
+ // }
+
+
instance.on("close", () => {
- if (rsPort) rsPort.close();
- if (ws) ws.close();
+ if(rsPort) rsPort.close();
+ if(ws) ws.close();
+ clearInterval(sendRebuildTasksAt11);
})
- function getPin(line) {
- //conversionTable
- let keys = Object.keys(pinsData);
- for (let i = 0; i < keys.length; i++) {
- let key = keys[i];
+ loadAllDb();
- if (pinsData[key].type == "state_of_contactor" && pinsData[key].line == line) {
- if (rsPort) return key - 1;
- if (ws) return key;
+ function getPin(line)
+ {
+ //conversionTable
+ let keys = Object.keys(pinsData);
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+
+ if(pinsData[key].type == "state_of_contactor" && pinsData[key].line == line)
+ {
+ if(rsPort) return key - 1;
+ if(ws) return key;
+ }
}
- }
- logger.debug("no pin detected");
+ logger.debug("no pin detected");
- return null;
+ return null;
}
- function turnAlarm(onOrOff) {
- let value = 0;
- if (onOrOff == "on") value = 1;
+ function turnOnAlarm()
+ {
+ if(FLOW.OMS_maintenance_mode) return;
- if (value == 1 && SETTINGS.maintenance_mode) return;
+ alarmStatus = "ON";
- alarmStatus = "OFF";
- if (value == 1) alarmStatus = "ON";
-
- if (rsPort) {
+ if(rsPort)
+ {
let arr = [0x55];
- arr.push(13);
- arr.push(0);
- arr.push(value);
-
+ arr.push( 13 );
+ arr.push( 0 );
+ arr.push( 1 );
+
rsPort.write(Buffer.from(arr), function(err) {
- logger.debug(`sirena - ${onOrOff}`);
+ logger.debug("sirena zapnuta");
});
}
- else if (ws) {
- let cmd = { "cmd": "set", "dev": "relay", "circuit": "1_01", "value": value };
+ else if(ws)
+ {
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1};
ws.send(JSON.stringify(cmd));
- logger.debug(`sirena - ${onOrOff}`);
+ logger.debug("sirena zapnuta");
}
}
- function reportLineStatus(line) {
+ function turnOffAlarm()
+ {
+ alarmStatus = "OFF";
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( 13 );
+ arr.push( 0 );
+ arr.push( 0 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ logger.debug("sirena vypnuta");
+ });
+ }
+ else if(ws)
+ {
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0};
+ ws.send(JSON.stringify(cmd));
+ logger.debug("sirena vypnuta");
+ }
+ }
+
+
+ function reportLineStatus(line)
+ {
//Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false).
+
let tbname = relaysData[line].tbname;
+
let bits = [];
- if (deviceStatus["state_of_breaker"][line] == "On") {
+ if(deviceStatuses["state_of_breaker"][line] == "On")
+ {
bits.push(0);
}
else bits.push(1);
- if (deviceStatus["state_of_contactor"][line] == "On") {
+ if(deviceStatuses["state_of_contactor"][line] == "On")
+ {
bits.push(0);
}
else bits.push(1);
@@ -452,420 +622,600 @@ exports.install = function(instance) {
let byte = bitwise.byte.write(bits.reverse());
//console.log("line", line, bits, byte);
- sendTelemetry({ statecode: byte }, tbname);
+
+ let values = {
+ statecode: byte
+ }
+
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+
+ //console.log(values);
+
+ instance.send(SEND_TO.tb, dataToTb);
}
- // turn line on or off
- function turnLine(onOrOff, line, pin, force, info) {
- //onOrOff => "on" or "off"
- let value = 0;
- if (onOrOff == "on") value = 1;
+ function turnOnLine(line, pin, force, info)
+ {
- if (force == undefined) force = false;
+ instance.send(SEND_TO.debug, "turn on line " + line );
+ if(force == undefined) force = false;
- if (line == 0) {
- if (value == 1 && alarmStatus == "ON") turnAlarm("off");
- SETTINGS.maintenance_mode = value ? true : false;
+ if(line == 0)
+ {
+ if(alarmStatus == "ON") turnOffAlarm();
+ FLOW.OMS_maintenance_mode = true;
let values = {};
values["statecode"] = calculateStateCode();
- values["power_mode"] = value ? "maintenance" : "Automatic";
- sendTelemetry(values, rvoTbName);
+ values["power_mode"] = "maintenance";
+ let tbname = relaysData[line].tbname;
+ sendTelemetry(values, tbname);
+
+ monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info);
- monitor.info(`turnLine ${onOrOff} - (line, SETTINGS.maintenance_mode)`, line, SETTINGS.maintenance_mode, info);
return;
}
- if (pin === undefined) pin = getPin(line);
+ if( pin === undefined) pin = getPin(line);
- if (pin === undefined) {
- errLogger.error("pin is undefined!", line);
+ monitor.info("turnOnLine (line, pin, force)", line, pin, force, info);
+
+ if( pin === undefined)
+ {
+ monitor.info("pin is undefined!", line);
return;
}
- if (!force) {
- if (relaysData[line].contactor == value) {
- instance.send(SEND_TO.debug, `line is already ${onOrOff} ` + line);
- logger.debug(`Dido: turnLine: line is already ${onOrOff} `, line);
+
+ if(!force)
+ {
+ if(relaysData[line].contactor == 1)
+ {
+ instance.send(SEND_TO.debug, "line is already on " + line );
+ logger.debug("turnOnLine: line is already on: ", line);
+
return;
}
}
// if(!rsPort.isOpen && !ws)
- if (!rsPort && !ws) {
- errLogger.error("Dido - port or websocket is not opened");
+ if(!rsPort && !ws)
+ {
+ errLogger.error("dido controller - port or websocket is not opened");
return;
}
- if (rsPort) {
+ if(rsPort)
+ {
let arr = [0x55];
- arr.push(pin);
- arr.push(0);
- arr.push(value);
-
+ arr.push( pin );
+ arr.push( 0 );
+ arr.push( 1 );
+
rsPort.write(Buffer.from(arr), function(err) {
- if (err === undefined) {
- monitor.info(`Dido: turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
+ if(err === undefined)
+ {
+ console.log("turnONLine zapisal do rsPortu", line, arr);
switchLogic(arr);
}
- else {
- monitor.info(`Dido: turnLine ${onOrOff} WRITE error`, err);
+ else
+ {
+ monitor.info("turnOnLine WRITE error", err);
}
+
});
}
- else if (ws) {
- //pin = "ro1_03" or "di1_01" ... we must make just "1_01" with slice method
- monitor.info(`Dido: turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
- let cmd = { "cmd": "set", "dev": "relay", "circuit": pin.slice(2), "value": value };
+ else if(ws)
+ {
+ console.log("turnONLine pin (relay)", pin);
+ //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
ws.send(JSON.stringify(cmd));
+ //switchLogic(pin, 1)
}
-
- //if rvo is 24/7, it has just one switching profile point at 13:00. we do not want to send notification as it repeats every day.
- //const d = new Date();
- //if(d.getHours() != 13) sendNotification("Dido_controller: ", SETTINGS.rvoTbName, "switching_profile_point_applied_to_line", { line: line, value: onOrOff }, "", SEND_TO.tb, instance);
}
- // main opening
- instance.on("2", _ => {
- main();
- })
+ function turnOffLine(line, pin, force, info)
+ {
+ if(force == undefined) force = false;
+
+ if(line == 0)
+ {
+ FLOW.OMS_maintenance_mode = false;
+
+ let values = {};
+ values["statecode"] = calculateStateCode();
+ values["power_mode"] = "automatic";
+ let tbname = relaysData[line].tbname;
+ sendTelemetry(values, tbname);
+
+ return;
+ }
+
+ if( pin === undefined) pin = getPin(line);
+
+ monitor.info("turnOffLine (line, pin, force)", line, pin, force, info);
+
+ if( pin === undefined)
+ {
+ errLogger.error("pin is undefined!", line);
+ return;
+ }
+
+ if(!force)
+ {
+ if(relaysData[line].contactor == 0)
+ {
+ instance.send(SEND_TO.debug, "line is already off " + line );
+ logger.debug("turnOffLine: line already off:", line);
+
+ return;
+ }
+ }
+
+ // if(!rsPort.isOpen && !ws)
+ if(!rsPort && !ws)
+ {
+ errLogger.error("di do controller - port or websocket is not opened");
+ return;
+ }
+
+ if(rsPort)
+ {
+ let arr = [0x55];
+ arr.push( pin );
+ arr.push( 0 );
+ arr.push( 0 );
+
+ rsPort.write(Buffer.from(arr), function(err) {
+ if(err === undefined)
+ {
+ console.log("turnOffLine zapisal do rsPort-u", line, arr);
+ switchLogic(arr);
+ }
+ else
+ {
+ monitor.info("turnOffLine WRITE error", err);
+ }
+
+ });
+
+ }
+ else if(ws)
+ {
+ //pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
+ //monitor.info("turnOffLine pin (relay)", pin);
+ let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0};
+ ws.send(JSON.stringify(cmd));
+ //switchLogic(pin, 0)
+ }
+
+ }
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device
instance.on("0", flowdata => {
- if (!isObject(flowdata.data)) return;
+ if(!flowdata.data instanceof Object) return;
// console.log('***********************', flowdata.data)
instance.send(SEND_TO.debug, flowdata.data);
// we handle nok status from modbus_reader component and thermometer
- if ("status" in flowdata.data) {
+ if(flowdata.data?.status)
+ {
const status = flowdata.data.status;
- if (status == "NOK-twilight_sensor") {
- deviceStatus["twilight_sensor"] = "NOK";
+ if(status == "NOK-twilight_sensor")
+ {
+ deviceStatuses["twilight_sensor"] = "NOK";
}
- else if (status == "NOK-em340" || status == "NOK-em111") {
- deviceStatus["em"] = "NOK";
+ else if(status == "NOK-em340" || status == "NOK-em111")
+ {
+ deviceStatuses["em"] = "NOK";
}
- else if (status == "NOK-thermometer") {
- deviceStatus["temperature"] = "NOK";
+ else if(status == "NOK-thermometer")
+ {
+ deviceStatuses["temperature"] = "NOK";
}
}
- else if ("values" in flowdata.data) {
+ else if(flowdata.data?.values)
+ {
const values = flowdata.data.values;
- if (values.hasOwnProperty("twilight_sensor")) {
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"] });
- deviceStatus["twilight_sensor"] = "OK"
+ if(values.hasOwnProperty("twilight_sensor"))
+ {
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"]});
+ deviceStatuses["twilight_sensor"] = "OK"
}
- else if (values.hasOwnProperty("temperature")) {
- deviceStatus["temperature"] = "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")) {
- deviceStatus["em"] = "OK";
- SETTINGS.no_voltage.size > 0 ? deviceStatus["no_voltage"] = "NOK" : deviceStatus["no_voltage"] = "OK";
+ else if(values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current"))
+ {
+ deviceStatuses["em"] = "OK";
+ }
+ else
+ {
+ return;
}
- sendTelemetry(values, rvoTbName);
+ const updateStatus = checkFinalRVOStatus();
+ if(updateStatus) values.status = "OK";
+
+ sendTelemetry(values, FLOW.OMS_rvo_tbname);
}
- sendRvoStatus();
})
-
-
// we expect array as flowdata.data
instance.on("1", flowdata => {
- //console.log(flowdata.data);
+ console.log(flowdata.data);
- if (!flowdata.data instanceof Object) return;
+ 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 == "on") turnLine("on", line, undefined, force, info);
- else if (obj.command == "off") turnLine("off", line, undefined, force, info);
- else if (obj.command == "turnOnAlarm") turnAlarm("on");
- else if (obj.command == "turnOffAlarm") turnAlarm("off");
+ if(obj.command == "turnOn") turnOnLine(line, undefined, force, info);
+ else if(obj.command == "turnOff") turnOffLine(line, undefined, force, info);
+ else if(obj.command == "turnOnAlarm") turnOnAlarm();
+ else if(obj.command == "turnOffAlarm") turnOffAlarm();
+
+
+ //! ake data prichadzaju z cmd_manager.js ???
+ //TODO transform to websocket
+ if (Array.isArray(obj)){
+
+ rsPort.write(Buffer.from(obj), function(err) {
+ switchLogic(obj);
+
+ instance.send(SEND_TO.debug, {"WRITE":obj} );
+ });
+ }
})
- function calculateStateCode() {
+ function calculateStateCode()
+ {
+ let bytes = [];
let bits = [];
- //Hlavny istic - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
- if (deviceStatus["state_of_main_switch"] === "closed" || deviceStatus["state_of_main_switch"] === "Off") {
+ //Hlavný istič - state_of_main_switch
+ if(deviceStatuses["state_of_main_switch"] == "On")
+ {
bits.push(0);
}
- else {
+ else if(deviceStatuses["state_of_main_switch"] == "Off")
+ {
bits.push(1);
}
- //Prevadzkovy mod - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
- if (!SETTINGS.maintenance_mode) {
- if (deviceStatus["rotary_switch_state"] === "Manual") {
+ //Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
+ if(!FLOW.OMS_maintenance_mode)
+ {
+ if(deviceStatuses["rotary_switch_state"] == "Manual")
+ {
bits.push(0);
bits.push(1);
}
- if (deviceStatus["rotary_switch_state"] === "Automatic") {
+ if(deviceStatuses["rotary_switch_state"] == "Automatic")
+ {
bits.push(0);
bits.push(0);
}
- if (deviceStatus["rotary_switch_state"] === "Off") {
+ if(deviceStatuses["rotary_switch_state"] == "Off")
+ {
bits.push(1);
bits.push(0);
}
}
- else {
+ else{
bits.push(1);
bits.push(1);
}
- //Dverovy kontakt
- if (deviceStatus["door_condition"] === "closed") {
+ //Dverový kontakt
+ if(deviceStatuses["door_condition"] == "closed")
+ {
bits.push(0);
}
- else {
+ else
+ {
bits.push(1);
}
//EM
- if (deviceStatus["em"] === "NOK") {
+ if(deviceStatuses["em"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
//Teplomer
- if (deviceStatus["temperature"] === "NOK") {
+ if(deviceStatuses["temperature"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
//Batéria
- if (deviceStatus["battery"] === "NOK") {
+ if(deviceStatuses["battery"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
//Zdroj
- if (deviceStatus["power_supply"] === "NOK") {
+ if(deviceStatuses["power_supply"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
//MN
- if (deviceStatus["master_node"] === "NOK") {
+ if(deviceStatuses["master_node"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
//výpadok napätia na fáze
- if (deviceStatus["no_voltage"] === "NOK") {
+ if(deviceStatuses["no_voltage"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
- if (deviceStatus["twilight_sensor"] === "NOK") {
+ if(deviceStatuses["twilight_sensor"] == "NOK")
+ {
bits.push(1);
}
- else {
+ else
+ {
bits.push(0);
}
-
+
// doplnime do 16 bitov (2 byty)
- for (let i = bits.length; i < 16; i++) {
+ for(let i = bits.length; i < 16; i++)
+ {
bits.push(0);
}
-
- // console.log("calculateStateCode - deviceStatus", deviceStatus);
+
+ // console.log("calculateStateCode - deviceStatuses", deviceStatuses);
// console.log("calculateStateCode", bits);
- let byte0 = bitwise.byte.write(bits.slice(0, 8).reverse());
+ let byte0 = bitwise.byte.write(bits.slice(0,8).reverse());
let byte1 = bitwise.byte.write(bits.slice(8).reverse());
let byte = bytesToInt([byte1, byte0]);
//console.log("calculateStateCode -------------------", byte);
-
+
return byte;
}
- async function sendRvoStatus() {
-
- if (SETTINGS === undefined) return;
- SETTINGS.masterNodeIsResponding ? deviceStatus["master_node"] = "OK" : deviceStatus["master_node"] = "NOK";
-
- const table = {
- "OK": 1,
- "NOK": 0
- };
-
- const dataToTb = {
- "electrometer_status": table[deviceStatus["em"]],
- "twilight_sensor_status": table[deviceStatus["twilight_sensor"]],
- "thermometer_status": table[deviceStatus["temperature"]],
- "phase_1_status": 1,
- "phase_2_status": 1,
- "phase_3_status": 1,
- "master_node_status": table[deviceStatus["master_node"]]
- };
-
- for (const phase of SETTINGS.no_voltage) dataToTb[`phase_${phase}_status`] = 0;
-
- dataToTb["status"] = checkRvoStatus();
- dataToTb["statecode"] = calculateStateCode();
-
- //console.log(dataToTb);
- sendTelemetry(dataToTb, rvoTbName);
- }
-
-
- function pinsForRvoStatus(controllerType, hasMainSwitch) {
-
- let pins = [];
-
- if (controllerType === "lm") {
- pins = [1, 4, 6];
- if (hasMainSwitch === 1) {
- pins = [4, 6];
- }
- } else if (controllerType === "unipi") {
- pins = ["di1_01", "di1_04", "di1_05"];
- if (hasMainSwitch === 1) {
- pins = ["di1_01", "di1_04"];
- }
- }
-
- return pins;
- }
-
-
- function checkRvoStatus() {
+ function checkFinalRVOStatus() {
// we check if any of these pins values are 0 --> it means status RVO is "NOK"
- // pinIndex 6 is door_condition - if it is opened in maintenance mode - status = OK
+ // pinIndex 6 is door_condition - if open in maintenance mode - status = OK
+
//set RVO state
+
let status = "OK";
- for (const [key, value] of Object.entries(deviceStatus)) {
- if (["em", "twilight_sensor", "temperature", "master_node"].includes(key) && value === "NOK") status = "NOK";
+ if(deviceStatuses["em"] == "NOK")
+ {
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: EM status is NOK");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: EM status is NOK");
+
+ status = "NOK";
}
- if (status === "OK") {
+ if(deviceStatuses["twilight_sensor"] == "NOK")
+ {
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: twilight_sensor is NOK");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: twilight sensor is NOK");
- let pinIndexes = pinsForRvoStatus(controller_type, hasMainSwitch);
+ status = "NOK";
+ }
+
+ //ak teplomer NOK, rvo nok
+ if(deviceStatuses["temperature"] == "NOK")
+ {
+
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK");
+
+ status = "NOK";
+ }
+
+ if(status == "OK")
+ {
+ let pinIndexes = [1, 4, 6];
+ if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
+
+ //console.log('-------- previousValues', previousValues);
for (const pinIndex of pinIndexes) {
if (previousValues[pinIndex] === 0) {
- if ((pinIndex === 6 || pinIndex === 'di1_01' || pinIndex === 'di1_05') && SETTINGS.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);
+
status = "NOK";
+
break;
}
}
}
// battery status. If value is 1 - battery is NOK
- if (previousValues[5] === 1) status = "NOK";
- if (SETTINGS.no_voltage.size > 0) status = "NOK";
+ if (previousValues[5] === 1)
+ {
+ let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery");
+ if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery");
- // console.log("rvo status",status)
- return status;
+ status = "NOK";
+ }
+
+ //console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding);
+
+ if(!FLOW.OMS_masterNodeIsResponding)
+ {
+ //errLogger.error("Master node is not responding");
+ errorHandler.sendMessageToService("Master node is not responding");
+ status = "NOK";
+
+ deviceStatuses["master_node"] = "NOK";
+ }
+ else deviceStatuses["master_node"] = "OK";
+
+ //console.log("checkFinalRVOStatus", status);
+ if(FLOW.OMS_no_voltage.size > 0)
+ {
+ let writeToFile = errorHandler.processMessage("no voltage detected");
+ if(writeToFile) errLogger.error("no voltage detected", FLOW.OMS_no_voltage);
+
+ status = "NOK";
+
+ deviceStatuses["no_voltage"] = "NOK";
+ }
+ else deviceStatuses["no_voltage"] = "OK";
+
+ if(status == "NOK")
+ {
+ sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname);
+
+ return false;
+ }
+
+ return true;
}
// we pass array to function in case of rsPort ==> switchLogic([55,3,0,1]) ==> [[55,3,0,1]]
- // we pass two values in case of websocket ==> switchLogic("ro1_03",1) ==> ["ro1_03",1]
+ // we pass two values in case of websocket ==> switchLogic("relay1_03",1) ==> ["relay1_03",1]
const switchLogic = (...args) => {
- let values = {};
- let pinIndex, newPinValue, twilight;
+ let values = {status: "OK"};
+ let dataToTb, pinIndex, newPinValue, twilight;
//data from rsPort
- if (args.length == 1) {
+ if(args.length == 1)
+ {
pinIndex = args[0][1] + 1;
if (pinIndex === 17) pinIndex--;
newPinValue = args[0][3];
twilight = args[0][2];
}
//data from websocket
- else {
+ else
+ {
pinIndex = args[0];
newPinValue = args[1];
}
let obj = pinsData[pinIndex];
- if (obj == undefined) {
+
+ if(obj == undefined)
+ {
previousValues[pinIndex] = newPinValue;
- //logger.debug("dido-switchLogic ==> no pinIndex", pinIndex);
return;
}
- //tbname is added to pinsData in initialSettings function
let type = obj.type;
let line = obj.line;
let tbname = obj.tbname;
//default value
- let value = "On";
- if (newPinValue === 0) value = "Off";
+ let value = "On";
+ if(newPinValue === 0) value = "Off";
- //Hlavny istic
- if (type === "state_of_main_switch" && hasMainSwitch) {
- if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance, "state_of_main_switch");
- deviceStatus["state_of_main_switch"] = "Off";
- }
- else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance, "state_of_main_switch");
- deviceStatus["state_of_main_switch"] = "On";
+ //Hlavný istič
+ //! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri
+ //! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition'
+ if(type === "!!!state_of_main_switch")
+ {
+ if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+ values["status"] = "NOK";
+
+ deviceStatuses["state_of_main_switch"] = "Off";
+ }
+ else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
+
+ deviceStatuses["state_of_main_switch"] = "On";
}
}
- //Prevadzkovy mod
- else if (type == "rotary_switch_state") {
+ //Prevádzkový mód
+ if(type == "rotary_switch_state")
+ {
// combination of these two pins required to get result
let pin2, pin3;
- if (pinIndex == 2 || pinIndex == "di1_02") {
+ if(pinIndex == 2 || pinIndex == "input1_02")
+ {
pin2 = newPinValue;
- pin3 = previousValues[3] || previousValues["di1_03"];
+ pin3 = previousValues[3] || previousValues["input1_03"];
- if (pin3 == undefined) {
+ if(pin3 == undefined)
+ {
previousValues[pinIndex] = newPinValue;
return;
- }
+ }
}
- else if (pinIndex == 3 || pinIndex == "di1_03") {
+ else if(pinIndex == 3 || pinIndex == "input1_03")
+ {
pin3 = newPinValue;
- pin2 = previousValues[2] || previousValues["di1_02"];
+ pin2 = previousValues[2] || previousValues["input1_02"];
- if (pin2 == undefined) {
+ if(pin2 == undefined)
+ {
previousValues[pinIndex] = newPinValue;
return;
- }
+ }
}
//console.log('***********************', pin2, pin3)
@@ -873,122 +1223,153 @@ exports.install = function(instance) {
if (pin2 == 0 && pin3 == 0) value = "Off";
if (pin2 == 0 && pin3 == 1) value = "Automatic";
- deviceStatus["rotary_switch_state"] = value;
+ deviceStatuses["rotary_switch_state"] = value;
//automatic - profilu pre nody sa vykonavaju
//ak je spracovany, a automatic - tak ho zapnem
//ak nie je spracovany, iba profil zapisem
-
- if (pin2 != undefined && pin3 != undefined) instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "rotary_switch_state", value: value });
+
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "rotary_switch_state", value: value});
//console.log("rotary_switch_state pin", pin2, pin3, value);
}
-
//Zdroj - pin 4
- else if (type === "power_supply") {
- if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
+ else if (type === "power_supply")
+ {
+ if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
+ values["status"] = "NOK";
- deviceStatus["power_supply"] = "NOK";
+ deviceStatuses["power_supply"] = "NOK";
}
- else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
+ else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
- deviceStatus["power_supply"] = "OK";
+ deviceStatuses["power_supply"] = "OK";
}
}
+ //Batéria - pin 5
+ else if (type === "battery")
+ {
+ if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
+ values["status"] = "NOK";
- //Bateria - pin 5
- else if (type === "battery") {
- if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
-
- deviceStatus["battery"] = "NOK";
+ deviceStatuses["battery"] = "NOK";
}
- else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
- sendNotification("switchLogic", rvoTbName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
+ else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
- deviceStatus["battery"] = "OK";
+ deviceStatuses["battery"] = "OK";
}
}
-
- //Dverovy kontakt - pin 6
- //! Ak je rvo s dvoma dverovymi kontaktami, ked pride z evoku signal z di1_05, co bol predytm "state_of_main switch" handlujeme ho teraz ako 'door_condition'
- else if (type == "door_condition" || type === "state_of_main_switch") {
+ //Dverový kontakt - pin 6
+ //! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch"
+ //! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
+ else if(type == "door_condition" || type === "state_of_main_switch")
+ {
newPinValue === 0 ? value = "open" : value = "closed";
- let door = "door_main";
- if (type === "state_of_main_switch") door = "door_em";
-
- if (value === "open") {
- if (SETTINGS.maintenance_mode) {
- sendNotification("switchLogic", rvoTbName, door + "_open", {}, "", SEND_TO.tb, instance, door);
- } else {
- sendNotification("switchLogic", rvoTbName, door + "_open_without_permission", {}, "", SEND_TO.tb, instance, door);
-
- // zapneme sirenu
- // ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
- if (type === "door_condition") turnAlarm("on");
- }
+ if (newPinValue != previousValues[pinIndex])
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", SEND_TO.tb, instance, "rvo_door");
+ //TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", SEND_TO.tb, instance, "rvo_door");
}
-
- if (value === "closed") {
- if (alarmStatus == "ON") turnAlarm("off");
- sendNotification("switchLogic", rvoTbName, door + "_close", {}, "", SEND_TO.tb, instance, door);
+ if (value === "open" && FLOW.OMS_maintenance_mode)
+ {
+ sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", SEND_TO.tb, instance, "rvo_door");
}
- deviceStatus[type] = value;
+ if (value === "open" && !FLOW.OMS_maintenance_mode)
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance);
+ sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", SEND_TO.tb, instance, "rvo_door");
+ values["status"] = "NOK";
+
+ //console.log(door_has_been_open_without_permision_alarm_is_on);
+
+ // zapneme sirenu
+ // ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
+ if(type === "door_condition") turnOnAlarm();
+ }
+
+ if (value === "closed")
+ {
+ if(alarmStatus == "ON") turnOffAlarm();
+ //turnOffAlarm();
+
+ sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
+ }
+
+ deviceStatuses["door_condition"] = value;
+
}
-
//lux sensor
- else if (type == "twilight_sensor") {
- //! TODO - to show nok status, if lux value is not changing more then 10 times.
+ else if(type == "twilight_sensor")
+ {
+ //! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000.
//Daylight is far more than 1000. So most of the day, when it is sunshine comes just value 1000. But lux sensor is not NOK.
//This is not the case in LM. If value from LM is the same 10x, there is 99% possibility, that sensor is NOK.
+ values["status"] = "OK";
value = newPinValue;
- if (controller_type === 'lm') {
- value = parseFloat(newPinValue + (256 * twilight));
+ if(controller_type === 'lm')
+ {
+ value = parseFloat(newPinValue + (256*twilight));
let now = new Date();
//new Date(dusk.getTime()
- let obj = { timestamp: now.getTime(), value: value };
+ 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) {
+ if(twilight_sensor_array.length > 10) {
let set = new Set(twilight_sensor_array);
- if (set.size === 1 && !twilightError) {
+ if(set.size === 1 && !twilightError)
+ {
twilightError = true;
+ values["status"] = "NOK";
let value = twilight_sensor_array.shift();
-
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance );
newPinValue = 0;
}
- else if (set.size !== 1 && twilightError) {
- //sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
+ else if (set.size !== 1 && twilightError)
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
twilightError = false;
twilight_sensor_array.shift();
-
newPinValue = value;
}
- else if (set.size === 1 && twilightError) {
+ 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) {
+
+ let diff = twilight_sensor[ twilight_sensor.length - 1 ].timestamp - twilight_sensor[0].timestamp;
+ if(diff >= twilight_sensor_interval * 60 * 1000)
+ {
const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length;
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "lux_sensor", value: average });
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "lux_sensor", value: average});
twilight_sensor = [];
@@ -997,118 +1378,212 @@ exports.install = function(instance) {
//else console.log("lux_sensor", value, diff);
}
}
+ else if(type == "state_of_contactor")
+ {
+ //sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", SEND_TO.tb, instance );
- else if (type == "state_of_contactor") {
- if (!(deviceStatus["state_of_contactor"][line] == value)) {
- sendNotification("switchLogic", rvoTbName, "state_of_contactor_for_line", { line: line, value: value }, "", SEND_TO.tb, instance);
+ if(!(deviceStatuses["state_of_contactor"][line] == value))
+ {
+ sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
}
-
- deviceStatus["state_of_contactor"][line] = value;
+ else
+ {
+ deviceStatuses["state_of_contactor"][line] = value;
+ }
//true, false
- if (value === "On") value = true;
- else if (value === "Off") value = false;
+ if(value === "On") value = true;
+ else if(value === "Off") value = false;
- //TODO do we need to modify relays table with contactor value, if we do not use it on startup ??
- let dataChanged = false;
- if (relaysData[line].contactor !== newPinValue) {
- dataChanged = true;
- relaysData[line].contactor = newPinValue;
- }
+ //modify table relays
+ dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged });
- reportLineStatus(line);
+ builder.callback(function(err, response) {
+
+ /*
+ if(useTurnOffCounter)
+ {
+ turnOffCounter--;
+
+ if(turnOffCounter <= 0)
+ {
+ useTurnOffCounter = false;
+ }
+ }
+ */
+
+ if(err == undefined)
+ {
+
+ let time = 0;
+ if(value) time = 1000 * 10;//10 sekund
+
+ let dataChanged = false;
+ if(relaysData[line].contactor != value) dataChanged = true;
+ relaysData[line].contactor = value;
+
+ //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
+ //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
+
+ setTimeout(function(){
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
+ }, time);
+
+ reportLineStatus(line);
+
+
+ }
+ else
+ {
+ errLogger.error("modify table relays failed", err);
+ }
+
+
+ });
+ });
}
- else if (type === "state_of_breaker") {
+ if(type === "state_of_breaker")
+ {
let valueChanged = false;
- if (newPinValue != previousValues[pinIndex]) valueChanged = true;
+ if(newPinValue != previousValues[pinIndex]) valueChanged = true;
- if (valueChanged) {
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line });
+ if(valueChanged)
+ {
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line});
//mame iba 3 istice. vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia (napr linia 1, paralelna s nou je linia 4, key je string "4")
// ak je 7 linii, na 1 istici je linia 1,4,7
- if (line == 1) {
+ if(line == 1)
+ {
- const lineOnSameBraker = [4, 7];
+ const lineOnSameBraker = [4,7];
- for (var i = 0; i < lineOnSameBraker.length; i++) {
- if (!relaysData.hasOwnProperty(lineOnSameBraker[i])) continue;
+ for (var i = 0; i < lineOnSameBraker.length; i++)
+ {
+ if(!relaysData.hasOwnProperty(lineOnSameBraker[i])) continue;
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i] });
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i]});
- deviceStatus["state_of_breaker"][lineOnSameBraker[i]] = value;
+ deviceStatuses["state_of_breaker"][lineOnSameBraker[i]] = value;
reportLineStatus(lineOnSameBraker[i]);
values[type] = value;
const tbname = relaysData[lineOnSameBraker[i]].tbname;
sendTelemetry(values, tbname);
-
+
delete values[type];
}
}
- else {
+ else
+ {
const lineOnSameBraker = line + 3 + "";
- if (relaysData.hasOwnProperty(lineOnSameBraker)) {
- instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3 });
+ if(relaysData.hasOwnProperty(lineOnSameBraker))
+ {
+ instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3});
- deviceStatus["state_of_breaker"][line + 3] = value;
+ deviceStatuses["state_of_breaker"][line + 3] = value;
reportLineStatus(line + 3);
values[type] = value;
const tbname = relaysData[lineOnSameBraker].tbname;
sendTelemetry(values, tbname);
-
+
delete values[type];
}
+
}
}
- if (value == "Off") values["status"] = "NOK";
- deviceStatus["state_of_breaker"][line] = value;
+ if(value == "Off") values["status"] = "NOK";
+
+ deviceStatuses["state_of_breaker"][line] = value;
reportLineStatus(line);
}
- else return;
values[type] = value;
+
+ //if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode();
- if (type == "rotary_switch_state") {
- if (SETTINGS.maintenance_mode) value = "maintenance";
- value = value.toLowerCase();
- values["power_mode"] = value;
+ if(pinsData.hasOwnProperty(pinIndex))
+ {
+ let valueChanged = false;
+ if(newPinValue != previousValues[pinIndex])
+ {
+ valueChanged = true;
+ //pin was changed
+ previousValues[pinIndex] = newPinValue;
+ }
+
+ let result = checkFinalRVOStatus();
+ if(!result && line == 0)
+ {
+ values["status"] = "NOK";
+ }
+
+ if(type == "state_of_contactor") valueChanged = true;
+ if(type == "rotary_switch_state") valueChanged = true;
+ if(type === "state_of_breaker")
+ {
+ //console.log(type, values, valueChanged);
+ }
+
+ if(FLOW.OMS_rvo_tbname == "")
+ {
+ console.log("FLOW.OMS_rvo_tbname is EMPTY");
+ }
+
+ if(FLOW.OMS_rvo_tbname == tbname)
+ {
+ values["statecode"] = calculateStateCode();
+ //console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname);
+ }
+
+ if(valueChanged)
+ {
+ sendTelemetry(values, tbname);
+ }
+
+ if(type == "rotary_switch_state")
+ {
+ if(FLOW.OMS_maintenance_mode) value = "maintenance";
+ value = value.toLowerCase();
+
+ let values = {};
+ values["power_mode"] = value;
+
+ sendTelemetry(values, tbname);
+ }
+ }
+ else
+ {
+ logger.debug("no pinIndex", pinsData[pinIndex], pinsData);
}
- if (newPinValue != previousValues[pinIndex]) previousValues[pinIndex] = newPinValue;
- if (Object.keys(values).length > 0 && tbname) sendTelemetry(values, tbname);
- }
+ }
- function sendTelemetry(values, tbname, date = Date.now()) {
+ function sendTelemetry(values, tbname)
+ {
let dataToTb = {
[tbname]: [
{
- "ts": date,
+ "ts": Date.now(),
"values": values
}
]
- };
+ }
- tbHandler.sendToTb(dataToTb, instance);
+ instance.send(SEND_TO.tb, dataToTb);
}
-
- function isObject(item) {
- return (typeof item === "object" && !Array.isArray(item) && item !== null);
- }
-
-} //end of instance
+}
@@ -1369,68 +1844,41 @@ exports.install = function(instance) {
//! pins.table --> from UNIPI
// pin:string|type:string|line:number
-// *|di1_01|state_of_main_switch|0|...........
-// *|di1_02|rotary_switch_state|0|...........
-// *|di1_03|rotary_switch_state|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|...........
-// *|di1_05|door_condition|0|...........
-// *|di1_06|state_of_breaker|1|...........
-// *|di1_07|state_of_breaker|2|...........
-// *|di1_08|state_of_breaker|3|...........
-// *|ro1_02|state_of_contactor|1|...........
-// *|ro1_03|state_of_contactor|2|...........
-// *|ro1_04|state_of_contactor|3|...........
+// *|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
// {
-// di1_01: {
-// pin: 'di1_01',
-// type: 'door_condition',
-// line: 0,
-// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
-// },
-// di1_02: {
-// pin: 'di1_02',
-// type: 'rotary_switch_state',
-// line: 0,
-// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
-// },
-// di1_03: {
-// pin: 'di1_03',
-// type: 'rotary_switch_state',
-// line: 0,
-// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
-// },
-// di1_04: {
-// pin: 'di1_04',
-// type: 'power_supply',
-// line: 0,
-// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
-// },
-// di1_05: {
-// pin: 'di1_05',
-// type: 'state_of_main_switch',
-// line: 0,
-// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
-// },
-// di1_06: {
-// pin: 'di1_06',
-// type: 'state_of_breaker',
-// line: 1,
-// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
-// },
-// ro1_02: {
-// pin: 'ro1_02',
-// type: 'state_of_contactor',
-// line: 1,
-// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
-// },
-// '28F46E9D0E00008B': { pin: '28F46E9D0E00008B', type: 'temperature', line: 0 },
-// twilight_sensor: { pin: 'twilight_sensor', type: 'twilight_sensor', line: 0 }
+// '16': { pin: '16', type: 'twilight_sensor', line: 0 },
+// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 },
+// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 },
+// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 },
+// al_power: { pin: 'al_power', type: 'power_supply', line: 0 },
+// al_battery: { pin: 'al_battery', type: 'battery', line: 0 },
+// al_door: { pin: 'al_door', type: 'door_condition', line: 0 },
+// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 },
+// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 },
+// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 },
+// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 },
+// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 },
+// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 },
+// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 },
+// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 },
+// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', line: 0 }
// }
+
//! relays_data
// {
// '0': {
diff --git a/flow/helper/DataToTbHandler.js b/flow/helper/DataToTbHandler.js
index ef6942a..8fff312 100644
--- a/flow/helper/DataToTbHandler.js
+++ b/flow/helper/DataToTbHandler.js
@@ -1,187 +1,163 @@
-class DataToTbHandler {
+class DataToTbHandler
+{
+ constructor(index) {
+ this.index = index;
- constructor(index) {
- this.index = index;
+ this.previousValues = {};
+ this.debug = false;
+ this.messageCounter = 0;
- // time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
- this.timeToHoldTbValue = 30 * 60; //30 minutes
- this.previousValues = {};
- this.debug = false;
- this.messageCounter = 0;
- this.itIsNodeReadout = false;
- this.sender = "";
+ this.sender = "";
+ }
- // if attribute change difference is less than limit value, we do not send to tb.
- this.attributeChangeLimit = {
- temperature: 0.5,
- Phase_1_voltage: 2,
- Phase_2_voltage: 2,
- Phase_3_voltage: 2,
- Phase_1_current: 0.1,
- Phase_2_current: 0.1,
- Phase_3_current: 0.1,
- Phase_1_power: 2,
- Phase_2_power: 2,
- Phase_3_power: 2,
- total_power: 2,
- total_energy: 1,
- Phase_1_pow_factor: 0.1,
- Phase_2_pow_factor: 0.1,
- Phase_3_pow_factor: 0.1,
- power_factor: 0.1,
- lifetime: 2,
- voltage: 2,
- power: 2,
- frequency: 3,
- energy: 0.1,
- current: 2,
- inclination_x: 10,
- inclination_y: 10,
- inclination_z: 10
- };
+ dump()
+ {
+ console.log("----------------------------");
+ console.log("previousValues", this.previousValues);
+ console.log("----------------------------");
+ }
- }
+ setSender(sender)
+ {
+ this.sender = sender;
+ }
- dump() {
- console.log("----------------------------");
- console.log("previousValues", this.previousValues);
- console.log("----------------------------");
- }
+ isEmptyObject( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ }
- setSender(sender) {
- this.sender = sender;
- }
+ sendToTb(dataToTb, instance)
+ {
- isEmptyObject(obj) {
- for (var _ in obj) {
- return false;
- }
- return true;
- }
+ if(!FLOW.OMS_brokerready)
+ {
+ return dataToTb;
+ }
+ let keys = Object.keys(dataToTb);
- sendToTb(data, instance) {
+ if(keys.length == 0)
+ {
+ if(this.debug) console.log("sendToTb received epty object", dataToTb);
+ return;
+ }
- //not to modify data object, we do deep copy:
- let dataCopy = JSON.parse(JSON.stringify(data));
+
+ let tbname = keys[0];
+ let ts;
- let keys = Object.keys(dataCopy);
+ let arrayOfValues = dataToTb[tbname];
+ let arrayOfValuesToSend = [];
- if (keys.length == 0) {
- if (this.debug) console.log("sendToTb received empty object", dataCopy);
- return;
- }
+ for(let i = 0; i < arrayOfValues.length; i++)
+ {
+ ts = arrayOfValues[i].ts;
- let tbname = keys[0];
- let ts;
+ //console.log("sendToTb------------>before", arrayOfValues[i].values, tbname);
- let arrayOfValues = dataCopy[tbname];
- let arrayOfValuesToSend = [];
+ let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
- for (let i = 0; i < arrayOfValues.length; i++) {
+ //console.log("sendToTb------------>after", values);
- ts = arrayOfValues[i].ts;
- let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
+ if(!this.isEmptyObject(values))
+ {
+ arrayOfValuesToSend.push({ts: ts, values: values});
+ }
+ }
- if (!this.isEmptyObject(values)) {
- arrayOfValuesToSend.push({ ts: ts, values: values });
- }
+ if(arrayOfValuesToSend.length == 0)
+ {
+ //if(this.debug) console.log("data not sent - empty array");
+ return;
+ }
- }
+ /*
+ let dataToTb = {
+ [tbname]: [
+ {
+ "ts": Date.now(),
+ "values": values
+ }
+ ]
+ }
+ */
- if (arrayOfValuesToSend.length == 0) {
- //if(this.debug) console.log("data not sent - empty array");
- return;
- }
+ this.messageCounter++;
- this.messageCounter++;
+ let dataToTbModified = {
+ [tbname]: arrayOfValuesToSend
+ }
- let dataToTbModified = {
- [tbname]: arrayOfValuesToSend
- }
+ //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
+ if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
+
+ instance.send(this.index, dataToTbModified);
+ }
- //console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
- //if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
- instance.send(this.index, dataToTbModified);
- }
+ getDiffTimestamp(key)
+ {
+ let seconds = 60*60;//1h
+ //seconds = 1;//for testing
+ //TODO set different value for given key!!!
+ //if(key == "status") seconds = 2*60*60;//2h
- getDiffTimestamp(key) {
- //TODO set different value for given key!!!
- //if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
- return this.timeToHoldTbValue * 1000;
- }
+ let timestampDiffToRemoveKey = seconds*1000;
+ return timestampDiffToRemoveKey;
+ }
- prepareValuesForTb(tbname, timestamp, values) {
+ prepareValuesForTb(tbname, timestamp, values)
+ {
+ let keys = Object.keys(values);
+ if(!this.previousValues.hasOwnProperty(tbname))
+ {
+ this.previousValues[tbname] = {};
+ }
- let keys = Object.keys(values);
+ //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
- if (keys.includes("lifetime")) this.itIsNodeReadout = true;
+ for(let i = 0; i < keys.length; i++)
+ {
+ let key = keys[i];
+ let value = values[key];
- if (!this.previousValues.hasOwnProperty(tbname)) {
- this.previousValues[tbname] = {};
- }
+ if(!this.previousValues[tbname].hasOwnProperty(key))
+ {
+ this.previousValues[tbname][key] = {ts: timestamp, value: value};
+ continue;
+ }
- //if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
+ if(this.previousValues[tbname][key].value === value)
+ {
+ let diff = timestamp - this.previousValues[tbname][key].ts;
- for (let i = 0; i < keys.length; i++) {
+ let timestampDiffToRemoveKey = this.getDiffTimestamp(key);
+ if(diff > timestampDiffToRemoveKey)
+ {
+ this.previousValues[tbname][key].ts = Date.now();
+ //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
- let key = keys[i];
- let value = values[key];
+ }
+ else
+ {
+ delete values[key];
+ //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
+ }
+ }
+ else
+ {
+ this.previousValues[tbname][key].value = value;
+ this.previousValues[tbname][key].ts = timestamp;
+ }
- if (!this.previousValues[tbname].hasOwnProperty(key)) {
- this.previousValues[tbname][key] = { ts: timestamp, value: value };
- continue;
- }
+ }
- // attributeData ==> {voltage: {ts:333333, value:5}}
- let attributeData = this.previousValues[tbname][key];
- let attributeToChange = false;
- if (key in this.attributeChangeLimit) attributeToChange = true;
- let limit = this.attributeChangeLimit[key];
- let timestampDiffToRemoveKey;
-
- //this will ensure "node statecode" will be sent just once an hour
- if (this.itIsNodeReadout && key === "statecode") {
- attributeData.value = value;
- this.itIsNodeReadout = false;
- timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
- }
-
- if (key === "twilight_sensor" && value > 100) {
- attributeData.value = value;
- }
-
- //if edge, master or node version do not change, send just once a day:
- if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
- timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
- }
-
- if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {
-
- let diff = timestamp - attributeData.ts;
- if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);
-
- if (diff > timestampDiffToRemoveKey) {
- attributeData.ts = Date.now();
- //if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
- }
- else {
- delete values[key];
- //if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
- }
- }
- else {
- attributeData.value = value;
- attributeData.ts = timestamp;
- }
-
- }
-
- return values;
- }
+ return values;
+ }
}
-module.exports = DataToTbHandler;
-
+module.exports = DataToTbHandler;
\ No newline at end of file
diff --git a/flow/helper/ErrorToServiceHandler.js b/flow/helper/ErrorToServiceHandler.js
index 2b27c32..dc60446 100644
--- a/flow/helper/ErrorToServiceHandler.js
+++ b/flow/helper/ErrorToServiceHandler.js
@@ -1,91 +1,124 @@
const { MD5 } = require('./md5.js');
const { networkInterfaces } = require('os');
-class ErrorToServiceHandler {
- constructor() {
+class ErrorToServiceHandler
+{
+ constructor() {
this.previousValues = {};
- this.project_id = undefined;
+ this.projects_id = undefined;
const nets = networkInterfaces();
- this.ipAddresses = {};
+ 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] = [];
}
this.ipAddresses[name].push(net.address);
}
}
}
+
+ //console.log(this.ipAddresses);
+
}
- setProjectId(project_id) {
- this.project_id = project_id;
+ setProjectsId(projects_id)
+ {
+ this.projects_id = projects_id;
}
- processMessage(message, seconds) {
- if (Array.isArray(message)) message = message.join(', ');
+ 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 ts = Date.now();
+ let timestamp = new Date().getTime();
- //keep in memory - default value is 1h
- if (seconds === undefined) seconds = 60 * 60;
+ //keep in memory
+ if (seconds === undefined) seconds = 60*60;
- if (!this.previousValues.hasOwnProperty(key)) {
- this.previousValues[key] = { ts: ts, duration: seconds };
+ if(!this.previousValues.hasOwnProperty(key))
+ {
+ this.previousValues[key] = {ts: timestamp, duration: seconds};
}
- let diff = (ts - this.previousValues[key].ts);
- if (diff < this.previousValues[key].duration * 1000) return false;
+ let diff = (timestamp - this.previousValues[key].ts);
+ if(diff < this.previousValues[key].duration*1000) return;
- this.previousValues[key].ts = ts;
+ this.previousValues[key].ts = timestamp;
+ */
- return message;
- }
+ //-------------------------
- sendMessageToService(message, seconds, message_type) {
-
- // if error occures too early FLOW.GLOBALS.settings.project_id is still undefined
- if (this.project_id === undefined) {
- console.log("ErrorToServiceHandler.js: no project_id");
- return;
- }
-
- let f = this.processMessage(message, seconds);
- if (f === false) return;
-
- if (message_type === undefined) message_type = "error_message";
-
- let toService = {
- id: this.project_id,
- ipAddresses: this.ipAddresses
- };
+ //send to service
+
+ let dataToInfoSender = {id: this.projects_id};
//js_error || error_message
- toService[message_type] = message;
+ dataToInfoSender[message_type] = message;
+ dataToInfoSender.ipAddresses = this.ipAddresses;
- console.log("ErrorToServiceHandler------------------------>send to service", toService);
+ 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(toService);
- builder.url('http://192.168.252.2:8004/sentmessage');
-
- builder.callback(function(err, response, output) {
- console.log("process.on error send", err, response, output, toService);
- });
+ 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 errorHandler = new ErrorToServiceHandler();
-
-
-module.exports = errorHandler;
-//module.exports = ErrorToServiceHandler;
+module.exports = ErrorToServiceHandler;
\ No newline at end of file
diff --git a/flow/helper/error_reporter.js b/flow/helper/error_reporter.js
new file mode 100644
index 0000000..2b84369
--- /dev/null
+++ b/flow/helper/error_reporter.js
@@ -0,0 +1,72 @@
+
+//key is device, value = str
+let sentValues= {};
+
+function sendError(func, device, weight, str, extra, tb_output, instance, type) {
+ // if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
+ // return; // Allow debug messages only if CONFIG.debug is active
+ // }
+
+ let key = device;
+ if(type != undefined) key = type;
+
+ if(sentValues.hasOwnProperty(key))
+ {
+ if(sentValues[key] == str)
+ {
+ return;
+ }
+ }
+
+ sentValues[key] = str;
+
+ let content = {
+ "type": weight,
+ "status": "new",
+ "source": {
+ "func":func,
+ "component":instance.id,
+ "component_name":instance.name,
+ "edge":device
+ },
+ "message":str,
+ "message_data": extra
+ };
+
+ let msg = {};
+ msg[device] = [
+ {
+ "ts": Date.now(),
+ "values": {
+ "_event":content
+ }
+ }
+ ];
+
+ // Msg can be outputted from components only after configuration
+ /*if (canSendErrData()){
+ sendBufferedErrors();
+ } else {
+ bufferError(msg);
+ }*/
+ instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
+
+}
+
+
+let ERRWEIGHT = {
+ EMERGENCY: "emergency", // System unusable
+ ALERT: "alert", // Action must be taken immidiately
+ CRITICAL: "critical", // Component unable to function
+ ERROR: "error", // Error, but component able to recover from it
+ WARNING: "warning", // Possibility of error, system running futher
+ NOTICE: "notice", // Significant message but not an error, things user might want to know about
+ INFO: "informational", // Info
+ DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
+};
+
+
+module.exports = {
+ sendError,
+ ERRWEIGHT
+}
\ No newline at end of file
diff --git a/flow/helper/error_reporting.js b/flow/helper/error_reporting.js
new file mode 100644
index 0000000..62dace5
--- /dev/null
+++ b/flow/helper/error_reporting.js
@@ -0,0 +1,56 @@
+const ERRWEIGHT = {
+ EMERGENCY: "emergency", // System unusable
+ ALERT: "alert", // Action must be taken immidiately
+ CRITICAL: "critical", // Component unable to function
+ ERROR: "error", // Error, but component able to recover from it
+ WARNING: "warning", // Possibility of error, system running futher
+ NOTICE: "notice", // Significant message but not an error, things user might want to know about
+ INFO: "informational", // Info
+ DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
+};
+
+
+
+
+function sendError(func, device, weight, str, extra){
+ if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
+ return; // Allow debug messages only if CONFIG.debug is active
+ }
+
+ let content = {
+ "type": weight,
+ "status": "new",
+ "source": {
+ "func":func,
+ "component":instance.id,
+ "component_name":instance.name,
+ "edge":myEdge
+ },
+ "message":str,
+ "message_data": extra
+ };
+ let msg = {};
+ msg[device] = [
+ {
+ "ts": Date.now(),
+ "values": {
+ "_event":content
+ }
+ }
+ ];
+
+ // Msg can be outputted from components only after configuration
+ /*if (canSendErrData()){
+ sendBufferedErrors();
+ } else {
+ bufferError(msg);
+ }*/
+ instance.send(0, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
+
+}
+
+
+module.exports = {
+ sendError,
+ ERRWEIGHT,
+}
\ No newline at end of file
diff --git a/flow/helper/logger.js b/flow/helper/logger.js
deleted file mode 100644
index 2585639..0000000
--- a/flow/helper/logger.js
+++ /dev/null
@@ -1,30 +0,0 @@
-//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
-//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
-
-var log4js = require("log4js");
-var path = require('path');
-
-log4js.configure({
-appenders: {
- errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'err.txt') },
- monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../../", 'monitor.txt') },
- console: { type: 'console' }
-},
-categories: {
- errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
- monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
- //another: { appenders: ['console'], level: 'trace' },
- default: { appenders: ['console'], level: 'trace' }
-}
-});
-
-const errLogger = log4js.getLogger("errLogs");
-const logger = log4js.getLogger();
-const monitor = log4js.getLogger("monitorLogs");
-
-//USAGE
-//logger.debug("text")
-//monitor.info('info');
-//errLogger.error("some error");
-
-module.exports = { errLogger, logger, monitor };
\ No newline at end of file
diff --git a/flow/helper/notification_reporter.js b/flow/helper/notification_reporter.js
index 839c12c..84b2345 100644
--- a/flow/helper/notification_reporter.js
+++ b/flow/helper/notification_reporter.js
@@ -1,9 +1,10 @@
-//key is device, value = message {}
-let sentValues = {};
-let notificationsData = null;
-let rvoName;
-//sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
+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
@@ -23,70 +24,87 @@ function getKey(map, val) {
//https://stackoverflow.com/questions/41117799/string-interpolation-on-variable
var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);
+async function initNotifications()
+{
+ let response = await promisifyBuilder(dbNotifications.find());
+ notificationsData = makeMapFromDbResult(response, "key");
-function initNotification() {
- notificationsData = FLOW.GLOBALS.notificationsData;
- rvoName = FLOW.GLOBALS.settings.rvo_name;
+ console.log("initNotifications done" );
}
-
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
+ // return;
+
let storeToSendValues = true;
- if (saveKey == undefined) storeToSendValues = false;
+ if(saveKey == undefined) storeToSendValues = false;
+ let lang = FLOW.OMS_language;
+ if(lang != "en" || lang != "sk") lang = "en";
+
+ let tpl = key;
let weight = "";
- let message = {};
- let notification = notificationsData[key];
+ if(notificationsData[key])
+ {
+ weight = notificationsData[key].weight;
+ weight = weight.toLowerCase();
- if (notification) {
- weight = notification.weight.toLowerCase();
-
- Object.keys(notification).forEach(item => {
- if (["en", "sk", "de", "cz", "it", "es"].includes(item)) {
- message[item] = rvoName + ": " + template(notification[item], params);
- }
- })
+ tpl = notificationsData[key][lang];
+ tpl = template(tpl, params);
}
- else {
- //console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
- console.error("sendNotification: Notifications: undefined key", key, func);
+ else
+ {
+ console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
return false;
}
//detect invalid err weight
- if (getKey(ERRWEIGHT, weight) == undefined) {
+ if(getKey(ERRWEIGHT, weight) == undefined)
+ {
console.error("sendNotification: Notifications: undefined weight", weight, key, func);
return false;
}
- if (sentValues.hasOwnProperty(saveKey)) {
- if (JSON.stringify(sentValues[saveKey]) == JSON.stringify(message)) {
+ if(sentValues.hasOwnProperty(saveKey))
+ {
+ if(sentValues[saveKey] == tpl)
+ {
return false;
}
}
- if (sentValues[saveKey] == undefined) {
- if (storeToSendValues) {
+ if(sentValues[saveKey] == undefined)
+ {
+ if(storeToSendValues)
+ {
//do not send - flow is was started
- sentValues[saveKey] = message;
+ sentValues[saveKey] = tpl;
return false;
}
}
- if (storeToSendValues) sentValues[saveKey] = message;
+ 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
+ "func":func,
+ "component":instance.id,
+ "component_name":instance.name,
+ "edge":device
},
- "message": message,
+ "message":str,
"message_data": extra
};
@@ -95,7 +113,7 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
{
"ts": Date.now(),
"values": {
- "_event": content
+ "_event":content
}
}
];
@@ -106,7 +124,6 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
} 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;
@@ -115,7 +132,6 @@ function sendNotification(func, device, key, params, extra, tb_output, instance,
module.exports = {
sendNotification,
- ERRWEIGHT,
- initNotification
-}
-
+ initNotifications,
+ ERRWEIGHT
+}
\ No newline at end of file
diff --git a/flow/helper/serialport_helper.js b/flow/helper/serialport_helper.js
index 7f5920d..a84ab84 100644
--- a/flow/helper/serialport_helper.js
+++ b/flow/helper/serialport_helper.js
@@ -1,99 +1,94 @@
const { exec } = require('child_process');
-function openPort(port) {
- return new Promise((resolve, reject) => {
+function openPort(port){
+ return new Promise((resolve, reject) => {
- var callbackError = function(err) {
- port.removeListener('error', callbackError);
- port.removeListener('open', callbackError);
+ var callbackError = function(err) {
+ port.removeListener('error', callbackError);
+ port.removeListener('open', callbackError);
- reject(err.message);
- };
+ reject(err.message);
+ };
- var callbackOpen = function(data) {
- port.removeListener('error', callbackError);
- port.removeListener('open', callbackOpen);
+ var callbackOpen = function(data) {
+ port.removeListener('error', callbackError);
+ port.removeListener('open', callbackOpen);
- resolve("port open: ok");
- };
+ resolve("port open: ok");
+ };
- port.on('error', callbackError);
- port.on('open', callbackOpen);
+ port.on('error', callbackError);
+ port.on('open', callbackOpen);
- port.open();
+ port.open();
- })
-}
+ })
+ }
-function runSyncExec(command) {
- return new Promise((resolve, reject) => {
+ function runSyncExec(command){
+ return new Promise((resolve, reject) => {
+
+ exec(command, (error, stdout, stderr) => {
+ if(error == null) resolve(stdout);
+ reject(error);
+ });
+
+ })
+ }
- exec(command, (error, stdout, stderr) => {
- if (error == null) resolve(stdout);
- reject(error);
- });
+ async function writeData(port, data, readbytes, timeout){
+ return new Promise((resolve, reject) => {
- })
-}
+ //readbytes = 0 = broadcast
+ if(readbytes == undefined) readbytes = 0;
+ if(timeout == undefined) timeout = 10000;//10s, default timeout MASTERA je 3s
-async function writeData(port, data, readbytes, timeout) {
- return new Promise((resolve, reject) => {
+ //cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
+
+ var callback = function(data) {
+ rsPortReceivedData.push(...data);
+ let l = rsPortReceivedData.length;
- // If first item in data array is 255, we just write broadcast command to rsPort
- // We wait 3 seconds and resolve(["broadcast"])
- // It is important to resolve with array
- if (data[0] == 255) {
+ if(l >= readbytes)
+ {
+ port.removeListener('data', callback);
+
+ clearTimeout(t);
+ resolve(rsPortReceivedData);
+ }
+ };
+
+ port.removeListener('data', callback);
+
+ let t = setTimeout(() => {
+ port.removeListener('data', callback);
+
+ console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
+
+ reject("TIMEOUT READING");
+ }, timeout);
+
+ let rsPortReceivedData = [];
+
+ if(readbytes > 0) port.on('data', callback);
port.write(Buffer.from(data), function(err) {
if (err) {
+ port.removeListener('data', callback);
reject(err.message);
}
+
+ if(readbytes == 0)
+ {
+ resolve(rsPortReceivedData);
+ }
+
});
-
- setTimeout(resolve, 3000, ["broadcast"]);
- return;
- }
-
- //cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
-
- var callback = function(data) {
- rsPortReceivedData.push(...data);
- let l = rsPortReceivedData.length;
-
- if (l >= readbytes) {
- port.removeListener('data', callback);
-
- clearTimeout(t);
- resolve(rsPortReceivedData);
- }
- };
-
- port.removeListener('data', callback);
-
- let t = setTimeout(() => {
- port.removeListener('data', callback);
-
- //console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
-
- reject("TIMEOUT READING");
- }, timeout);
-
- let rsPortReceivedData = [];
-
- port.on('data', callback);
-
- port.write(Buffer.from(data), function(err) {
- if (err) {
- port.removeListener('data', callback);
- reject(err.message);
- }
-
- });
- })
+ })
}
module.exports = {
openPort,
runSyncExec,
writeData
-}
+}
\ No newline at end of file
diff --git a/flow/helper/utils.js b/flow/helper/utils.js
index 57b0f89..a16210c 100644
--- a/flow/helper/utils.js
+++ b/flow/helper/utils.js
@@ -1,102 +1,56 @@
-function bytesToInt_orig(bytes, numberOfBytes) {
+function bytesToInt(bytes, numberOfBytes)
+{
+ let buffer = [];
+ if(Array.isArray(bytes))
+ {
+ buffer = bytes.slice(0);
+ if(numberOfBytes != undefined)
+ {
+ buffer = bytes.slice(bytes.length - numberOfBytes);
+ }
+ }
+ else buffer.push(bytes);
+
+ //var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
+ let l = (buffer.length - 1) * 8;
+
+ let decimal = 0;
+ for(let i = 0; i < buffer.length; i++)
+ {
+ var s = buffer[i] << l;
+ if(l < 8) s = buffer[i]
+ decimal = decimal + s;
+
+ l = l - 8;
- let buffer = [];
- if (Array.isArray(bytes)) {
- buffer = bytes.slice(0);
- if (numberOfBytes != undefined) {
- buffer = bytes.slice(bytes.length - numberOfBytes);
- }
- }
- else buffer.push(bytes);
- //var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
-
- let l = (buffer.length - 1) * 8;
- let decimal = 0;
- for (let i = 0; i < buffer.length; i++) {
- var s = buffer[i] << l;
- if (l < 8) s = buffer[i]
- decimal = decimal + s;
- l = l - 8;
- }
- // console.log("decimal utils.js: ", decimal);
-
- let decimal1 = 0n;
- for (let i = 0; i < buffer.length; i++) {
- decimal1 += BigInt(buffer[i]) * (2n ** BigInt((buffer.length - 1 - i) * 8));
- }
- // console.log("decimal biging utils.js: ", decimal1);
- return decimal;
+ }
+
+ return decimal;
}
-//bytestouintBE
-function bytesToInt(bytes, numberOfBytes) {
-
- let buffer = [];
- if (Array.isArray(bytes)) {
- buffer = bytes.slice(0);
- if (numberOfBytes != undefined) {
- buffer = bytes.slice(bytes.length - numberOfBytes);
- }
- }
- else buffer.push(bytes);
-
- console.log(bytes, buffer);
-
- let result = 0;
- for (let i = 0; i < buffer.length; i++) {
- result = (result << 8) | bytes[i];
- }
- // console.log("decimal biging utils.js: ", decimal1);
-
- console.log("originall: ", bytesToInt_orig(buffer));
- console.log("uint little endian: ", bytesToUintLE(buffer));
- console.log('neww: ', result >>> 0);
- return result >>> 0;
-}
-
-function bytesToUintLE(bytes, numberOfBytes) {
-
- let buffer = [];
- if (Array.isArray(bytes)) {
- buffer = bytes.slice(0);
- if (numberOfBytes != undefined) {
- buffer = bytes.slice(bytes.length - numberOfBytes);
- }
- }
- else buffer.push(bytes);
- //var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
-
- let result = 0;
- for (let i = buffer.length - 1; i <= 0; i--) {
- result = (result << 8) | bytes[i];
- }
- return result >>> 0;
-}
-
-
function resizeArray(arr, newSize, defaultValue) {
- while (newSize > arr.length)
- arr.push(defaultValue);
- arr.length = newSize;
+ while(newSize > arr.length)
+ arr.push(defaultValue);
+ arr.length = newSize;
}
longToByteArray = function(/*long*/long) {
- // we want to represent the input as a 8-bytes array
- var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
-
- for (var index = 0; index < byteArray.length; index++) {
- var byte = long & 0xff;
- byteArray[index] = byte;
- long = (long - byte) / 256;
- }
-
- return byteArray;
-};
+ // we want to represent the input as a 8-bytes array
+ var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
+
+ for ( var index = 0; index < byteArray.length; index ++ ) {
+ var byte = long & 0xff;
+ byteArray [ index ] = byte;
+ long = (long - byte) / 256 ;
+ }
+
+ return byteArray;
+ };
function addDays(date, days) {
- var result = new Date(date);
- result.setDate(result.getDate() + days);
- return result;
+ var result = new Date(date);
+ result.setDate(result.getDate() + days);
+ return result;
}
/*
@@ -107,64 +61,64 @@ sleep(2000).then(() => {
});
*/
-function sleep(time) {
- return new Promise((resolve) => setTimeout(resolve, time));
+function sleep (time) {
+ return new Promise((resolve) => setTimeout(resolve, time));
}
-function isEmptyObject(obj) {
- for (var name in obj) {
- return false;
- }
- return true;
+function isEmptyObject( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
}
function convertUTCDateToLocalDate(date) {
- var newDate = new Date(date);
- newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
- return newDate;
+ var newDate = new Date(date);
+ newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
+ return newDate;
}
function addZeroBefore(n) {
- return (n < 10 ? '0' : '') + n;
+ return (n < 10 ? '0' : '') + n;
}
-var convertBase = function() {
+var convertBase = function () {
- function convertBase(baseFrom, baseTo) {
- return function(num) {
- return parseInt(num, baseFrom).toString(baseTo);
-
- };
- }
-
- // binary to decimal
- convertBase.bin2dec = convertBase(2, 10);
-
- // binary to hexadecimal
- convertBase.bin2hex = convertBase(2, 16);
-
- // decimal to binary
- convertBase.dec2bin = convertBase(10, 2);
-
- // decimal to hexadecimal
- convertBase.dec2hex = convertBase(10, 16);
-
- // hexadecimal to binary
- convertBase.hex2bin = convertBase(16, 2);
-
- // hexadecimal to decimal
- convertBase.hex2dec = convertBase(16, 10);
-
- return convertBase;
-}();
+ function convertBase(baseFrom, baseTo) {
+ return function (num) {
+ return parseInt(num, baseFrom).toString(baseTo);
+
+ };
+ }
+
+ // binary to decimal
+ convertBase.bin2dec = convertBase(2, 10);
+
+ // binary to hexadecimal
+ convertBase.bin2hex = convertBase(2, 16);
+
+ // decimal to binary
+ convertBase.dec2bin = convertBase(10, 2);
+
+ // decimal to hexadecimal
+ convertBase.dec2hex = convertBase(10, 16);
+
+ // hexadecimal to binary
+ convertBase.hex2bin = convertBase(16, 2);
+
+ // hexadecimal to decimal
+ convertBase.hex2dec = convertBase(16, 10);
+
+ return convertBase;
+ }();
module.exports = {
- bytesToInt,
- longToByteArray,
- addDays,
- addZeroBefore,
- resizeArray,
- isEmptyObject,
- sleep,
- convertUTCDateToLocalDate
-}
+ bytesToInt,
+ longToByteArray,
+ addDays,
+ addZeroBefore,
+ resizeArray,
+ isEmptyObject,
+ sleep,
+ convertUTCDateToLocalDate
+}
\ No newline at end of file
diff --git a/flow/infosender.js b/flow/infosender.js
index 587724f..a83499c 100644
--- a/flow/infosender.js
+++ b/flow/infosender.js
@@ -3,9 +3,12 @@ exports.title = 'Info sender';
exports.version = '1.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
-exports.input = 2;
+exports.input = 1;
exports.output = 1
+exports.click = false;
+exports.author = 'oms-is';
exports.icon = 'bolt';
+exports.options = { edge: "undefined" };
const { networkInterfaces } = require('os');
@@ -19,12 +22,13 @@ exports.html = `
exports.readme = `# send all data to projects.worksys.io, required to monitor status of controller(unipi)`;
-exports.install = function(instance) {
+const fs = require('fs');
+var path = require('path');
- let id;
+exports.install = async function(instance) {
+
let allValues = {};
let sendAllValuesInterval;
- let configured = false;
let now = new Date();
console.log(exports.title, "INSTALLED", now.toLocaleString("sk-SK"));
@@ -33,49 +37,69 @@ exports.install = function(instance) {
let 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 (!ipAddresses[name]) {
- ipAddresses[name] = [];
- }
- ipAddresses[name].push(net.address);
+ 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 (!ipAddresses[name]) {
+ ipAddresses[name] = [];
+ }
+ ipAddresses[name].push(net.address);
+ }
}
- }
}
- function sendValues() {
- if (!configured) return;
+
+ function sendValues()
+ {
+ const id = FLOW.OMS_projects_id;
- if (Object.keys(allValues).length > 0) {
- let dataToSend = { ...allValues };
- dataToSend.id = id;
- dataToSend.ipAddresses = ipAddresses;
+ if(Object.keys(allValues).length > 0)
+ {
+ if(id !== undefined)
+ {
+ delete allValues.__force__;
+ let dataToSend = {...allValues};
+ dataToSend.id = id;
+ dataToSend.ipAddresses = ipAddresses;
+ //dataToSend.notify_date = new Date().toISOString().slice(0, 19).replace('T', ' ');
- instance.send(0, dataToSend);
+ //console.log(exports.title, "------------>sendValues", dataToSend);
+
+ instance.send(0, dataToSend);
+
+ allValues = {};
+ }
+ else
+ {
+ console.log(exports.title, "unable to send data, id is undefined");
+ }
- allValues = {};
}
}
-
+
instance.on("close", () => {
clearInterval(sendAllValuesInterval);
})
- instance.on("0", _ => {
- id = FLOW.GLOBALS.settings.project_id;
- if (id) configured = true;
- else console.log(exports.title, "InfoSender: Unable to send data, no id");
- })
+ instance.on("data", (flowdata) => {
+
+ allValues = { ...allValues, ...flowdata.data};
- instance.on("1", flowdata => {
- allValues = { ...allValues, ...flowdata.data };
//console.log("DATA RECEIVED", flowdata.data);
+
+ //__force__
+ if(flowdata.data.hasOwnProperty("__force__"))
+ {
+ if(flowdata.data.__force__)
+ {
+ sendValues();
+ }
+ }
})
sendAllValuesInterval = setInterval(() => {
sendValues();
- }, 60000 * 3);
-
+ }, 60000*3);
+
}
diff --git a/flow/modbus_reader.js b/flow/modbus_reader.js
index 5852ff3..f34ec9a 100644
--- a/flow/modbus_reader.js
+++ b/flow/modbus_reader.js
@@ -3,7 +3,6 @@ exports.title = 'Modbus reader';
exports.version = '2.0.0';
exports.group = 'Worksys';
exports.color = '#2134B0';
-exports.input = 1;
exports.output = ["red", "white", "yellow"];
exports.click = false;
exports.author = 'Rastislav Kovac';
@@ -16,7 +15,7 @@ exports.readme = `
`;
const modbus = require('jsmodbus');
-const {SerialPort} = require('serialport');
+const SerialPort = require('serialport');
const { timeoutInterval, deviceConfig } = require("../databases/modbus_config");
const { sendNotification } = require('./helper/notification_reporter');
@@ -32,16 +31,13 @@ const SEND_TO = {
const numberOfNotResponding = {};
let tbName = null;
let mainSocket;
-//number of phases inRVO
-let phases;
-//phases where voltage is 0 (set)
-let noVoltage;
+
exports.install = function(instance) {
class SocketWithClients {
- constructor() {
+ constructor () {
this.stream = null;
this.socket = null;
this.clients = {};
@@ -55,39 +51,31 @@ exports.install = function(instance) {
this.indexInDeviceConfig = 0; // first item in deviceConfig
this.lengthOfActualDeviceStream = null;
this.device = null;
-
+
// lampSwitchNotification helper variables
this.onNotificationSent = false;
this.offNotificationSent = false;
- this.phases = this.buildPhases();
this.startSocket();
}
- buildPhases = () => {
- let a = [];
- for (let i = 1; i <= phases; i++) {
- a.push(`Phase_${i}_voltage`)
- }
- return a;
- }
-
startSocket = () => {
let obj = this;
- this.socket = new SerialPort({path: "/dev/ttymxc0",
- baudRate: 9600
+ 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++) {
+ for( let i = 0; i < deviceConfig.length; i++)
+ {
this.clients[deviceConfig[i].deviceAddress] = new modbus.client.RTU(this.socket, deviceConfig[i].deviceAddress, 2000); // 2000 is timeout in register request, default is 5000, which is too long
}
this.socket.on('error', function(e) {
console.log('socket connection error', e);
- if (e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
+ if(e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') {
console.log(exports.title + ' Waiting 10 seconds before trying to connect again');
setTimeout(obj.startSocket, 10000);
}
@@ -98,7 +86,7 @@ exports.install = function(instance) {
setTimeout(obj.startSocket, 10000);
});
- this.socket.on('open', function() {
+ this.socket.on('open', function () {
console.log("socket connected");
obj.getActualStreamAndDevice();
obj.timeoutInterval = timeoutInterval - DELAY_BETWEEN_DEVICES; // to make sure readout always runs in timeoutinterval we substract DELAY_BETWEEN_DEVICES
@@ -111,11 +99,11 @@ exports.install = function(instance) {
this.index = 0;
this.errors = 0;
this.stream = dev.stream;
- this.lengthOfActualDeviceStream = dev.stream.length;
+ 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);
+ if(this.indexInDeviceConfig == 0) setTimeout(this.readRegisters, this.timeoutInterval);
else setTimeout(this.readRegisters, DELAY_BETWEEN_DEVICES);
}
@@ -129,18 +117,21 @@ exports.install = function(instance) {
let obj = this;
this.clients[this.deviceAddress].readHoldingRegisters(register, size)
- .then(function(resp) {
-
+ .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)) {
+ if(numberOfNotResponding.hasOwnProperty(obj.device))
+ {
let message = "";
- if (obj.device == "em340") {
+ if(obj.device == "em340")
+ {
message = "electrometer_ok";
}
- else if (obj.device == "twilight_sensor") {
+ else if(obj.device == "twilight_sensor")
+ {
message = "twilight_sensor_ok";
}
message && sendNotification("modbus_reader: readRegisters", tbName, message, {}, "", SEND_TO.tb, instance);
@@ -153,21 +144,25 @@ exports.install = function(instance) {
obj.index++;
obj.readAnotherRegister();
- }).catch(function() {
-
- //console.log("errors pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute);
+ }).catch (function () {
+ console.log("errors pri citani modbus registra", register, obj.indexInDeviceConfig, tbName, tbAttribute);
+
obj.errors++;
- if (obj.errors == obj.lengthOfActualDeviceStream) {
- instance.send(SEND_TO.dido_controller, { status: "NOK-" + obj.device }); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
-
+ if(obj.errors == obj.lengthOfActualDeviceStream)
+ {
+ instance.send(SEND_TO.dido_controller, {status: "NOK-" + obj.device}); // NOK-em340, NOK-em111, NOK-twilight_sensor, NOK-thermometer
+
//todo - neposlalo notification, ked sme vypojili twilight a neposle to do tb, ale do dido ??
- if (!numberOfNotResponding.hasOwnProperty(obj.device)) {
+ if(!numberOfNotResponding.hasOwnProperty(obj.device))
+ {
let message = "";
- if (obj.device == "twilight_sensor") {
+ if(obj.device == "twilight_sensor")
+ {
message = "twilight_sensor_nok";
}
- else if (obj.device == "em340") {
+ else if(obj.device == "em340")
+ {
message = "electrometer_nok";
}
message && sendNotification("modbus_reader: readingTimeouted", tbName, message, {}, "", SEND_TO.tb, instance);
@@ -175,16 +170,17 @@ exports.install = function(instance) {
}
obj.errors = 0;
- numberOfNotResponding[obj.device] += 1;
+ numberOfNotResponding[obj.device] += 1;
}
- // console.error(require('util').inspect(arguments, {
- // depth: null
- // }))
+ console.error(require('util').inspect(arguments, {
+ depth: null
+ }))
// if reading out of device's last register returns error, we send accumulated allValues to dido_controller (if allValues are not an empty object)
- if (obj.index + 1 >= obj.lengthOfActualDeviceStream) {
- if (!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, { values: obj.allValues });
+ if(obj.index + 1 >= obj.lengthOfActualDeviceStream)
+ {
+ if(!isObjectEmpty(obj.allValues)) instance.send(SEND_TO.dido_controller, {values: obj.allValues});
obj.allValues = {};
}
obj.index++;
@@ -194,7 +190,7 @@ exports.install = function(instance) {
};
readAnotherRegister = () => {
- if (this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0);
+ if(this.index < this.lengthOfActualDeviceStream) setTimeout(this.readRegisters, 0);
else this.setNewStream();
}
@@ -203,16 +199,18 @@ exports.install = function(instance) {
for (let i = 0; i < this.lengthOfActualDeviceStream; i++) {
let a = this.stream[i];
- if (a.register === register) {
+ if (a.register === register)
+ {
let tbAttribute = a.tbAttribute;
let multiplier = a.multiplier;
-
- let value = this.calculateValue(response, multiplier);
+
+ let value = this.calculateValue(response, multiplier);
// console.log(register, tbName, tbAttribute, response, a.multiplier, value);
// if(tbName == undefined) return;
- if (this.index + 1 < this.lengthOfActualDeviceStream) {
+ if(this.index + 1 < this.lengthOfActualDeviceStream)
+ {
this.allValues[tbAttribute] = value;
return;
}
@@ -225,45 +223,54 @@ exports.install = function(instance) {
this.checkNullVoltage(values);
this.lampSwitchNotification(values);
- instance.send(SEND_TO.dido_controller, { values: values });
+ instance.send(SEND_TO.dido_controller, {values: values});
this.allValues = {};
break;
}
- }
+
+ }
+
}
- setNewStream = () => {
- if (this.lengthOfActualDeviceStream == this.index) {
- if (this.indexInDeviceConfig + 1 == deviceConfig.length) {
+ setNewStream = () =>
+ {
+ if(this.lengthOfActualDeviceStream == this.index)
+ {
+ if(this.indexInDeviceConfig + 1 == deviceConfig.length)
+ {
this.indexInDeviceConfig = 0;
- }
- else {
+ }
+ else
+ {
this.indexInDeviceConfig += 1;
}
this.getActualStreamAndDevice();
- }
+ }
}
- calculateValue = (response, multiplier) => {
+ calculateValue = (response, multiplier) =>
+ {
let value = 0;
let l = response.length;
- if (l === 2) {
- value = (response[1] * (2 ** 16) + response[0]);
+ 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;
- }
+ 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) {
+ 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
+ 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;
+ value = value - "0xFFFF" + 1;
}
}
@@ -272,75 +279,70 @@ exports.install = function(instance) {
checkNullVoltage = (values) => {
- if (!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
+ if(!(values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_2_voltage") || values.hasOwnProperty("Phase_3_voltage"))) return;
Object.keys(values).map(singleValue => {
- if (this.phases.includes(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) {
- noVoltage.add(phase);
- sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", { phase: phase }, "", SEND_TO.tb, instance, "voltage" + phase);
+ if(values[singleValue] == 0)
+ {
+ FLOW.OMS_no_voltage.add(phase);
+ sendNotification("modbus_reader: checkNullVoltage", tbName, "no_voltage_on_phase", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase );
// console.log('no voltage')
}
- else {
- noVoltage.delete(phase);
+ else
+ {
+ FLOW.OMS_no_voltage.delete(phase);
// console.log('voltage detected')
- sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", { phase: phase }, "", SEND_TO.tb, instance, "voltage" + phase);
+ sendNotification("modbus_reader: checkNullVoltage", tbName, "voltage_on_phase_restored", {phase: phase}, "", SEND_TO.tb, instance, "voltage" + phase);
}
- }
+ }
})
}
/**
- * function sends notification to slack and to tb, if EM total_power value changes more than numberOfNodes*15. This should show, that RVO lamps has been switched on or off
- */
+ * function sends notification to slack and to tb, if EM total_power value changes more than 500. This should show, that RVO lamps has been switched on or off
+ */
lampSwitchNotification = (values) => {
- if (!values.hasOwnProperty("total_power")) return;
+ if(!values.hasOwnProperty("total_power")) return;
const actualTotalPower = values.total_power;
-
- const numberOfNodes = Object.keys(FLOW.GLOBALS.nodesData).length;
- if (numberOfNodes == 0) numberOfNodes = 20; // to make sure, we send notification if totalPower is more than 300
-
- if (actualTotalPower > numberOfNodes * 15 && this.onNotificationSent == false) {
+ if(actualTotalPower > 600 && this.onNotificationSent == false)
+ {
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_on", {}, "", SEND_TO.tb, instance);
this.onNotificationSent = true;
this.offNotificationSent = false;
- }
- else if (actualTotalPower <= numberOfNodes * 15 && this.offNotificationSent == false) {
+ }
+ else if(actualTotalPower <= 600 && this.offNotificationSent == false)
+ {
sendNotification("modbus_reader: lampSwitchNotification", tbName, "lamps_have_turned_off", {}, "", SEND_TO.tb, instance);
this.onNotificationSent = false;
this.offNotificationSent = true;
}
}
- }
+ }
const isObjectEmpty = (objectName) => {
- return Object.keys(objectName).length === 0 && objectName.constructor === Object;
+ return Object.keys(objectName).length === 0 && objectName.constructor === Object;
}
- function main() {
-
- phases = FLOW.GLOBALS.settings.phases;
- tbName = FLOW.GLOBALS.settings.rvoTbName;
- noVoltage = FLOW.GLOBALS.settings.no_voltage;
+ setTimeout(() => {
+
mainSocket = new SocketWithClients();
-
- console.log("novoltage: ", noVoltage, typeof noVoltage);
+ tbName = FLOW.OMS_rvo_tbname;
// this notification is to show, that flow (unipi) has been restarted
sendNotification("modbus_reader", tbName, "flow_restart", {}, "", SEND_TO.slack, instance);
- }
- instance.on("0", function(_) {
- main();
- })
+ }, 25000);
}
diff --git a/flow/nodesdb_changecheck.js b/flow/nodesdb_changecheck.js
deleted file mode 100644
index be1e700..0000000
--- a/flow/nodesdb_changecheck.js
+++ /dev/null
@@ -1,70 +0,0 @@
-exports.id = 'nodesdb_change_check';
-exports.title = 'Nodes DB change check';
-exports.group = 'Worksys';
-exports.color = '#888600';
-exports.version = '1.0.2';
-exports.icon = 'sign-out';
-exports.input = 1;
-exports.output = 1;
-exports.readme = `Check, if nodes.table db changed compared to original database`;
-
-const fs = require('fs');
-const path = require('path');
-const { sendNotification } = require('./helper/notification_reporter');
-const nodesOriginalFile = path.join(__dirname, '../databases/nodes_original/', 'nodes_original.table');
-
-
-exports.install = function(instance) {
-
- function compareArrays(array1, array2) {
- let message = "";
- let areEqual = true;
- let zmenene = []
-
- if (array1.length !== array2.length) {
- message += "Nezhoda v pocte nodov. "
- }
-
- const set1 = new Set(array1.map(obj => JSON.stringify(obj)));
- const set2 = new Set(array2.map(obj => JSON.stringify(obj)));
-
- for (const objStr of set1) {
-
- if (!set2.has(objStr)) {
- zmenene.push(objStr)
- areEqual = false;
- } else {
- set2.delete(objStr);
- }
- }
-
- if(!areEqual) {
- message += `Aktualne nody: ${zmenene.toString()}. Zmenene proti originalu: ${Array.from(set2).join(' ')}`;
- sendNotification("Nodesdb_changecheck", FLOW.GLOBALS.settings.rvoTbName, "nodes_db_changed", "", message, 0, instance);
- }
- else console.log("Arrays are equal.");
-
- console.log(message)
- }
-
-
- instance.on("data", _ => {
-
- let nodesData = FLOW.GLOBALS.nodesData;
-
- // we check if nodes.table has changed compared to nodes_original.table (we have array of nodes e.g. [{node:255, tbname: "agruhuwhgursuhgo34hgsdiguhrr"}]
- const nodes_actual = Object.keys(nodesData).map(node => ({[node]: nodesData[node].tbname}))
- let nodes_original = fs.readFileSync(nodesOriginalFile, { encoding: 'utf8', flag: 'r' });
-
- try {
- nodes_original = JSON.parse(nodes_original);
- } catch(e) {
- console.log(e)
- }
-
-
- setTimeout(() => compareArrays(nodes_actual, nodes_original),10000);
- })
-
-}
-
diff --git a/flow/notifikacie.csv b/flow/notifikacie.csv
new file mode 100644
index 0000000..520c997
--- /dev/null
+++ b/flow/notifikacie.csv
@@ -0,0 +1,31 @@
+key;weight;en;sk
+switching_profile_point_applied_to_line;INFO;Switching profile point applied to line no. ${line} : ${value};Aplikovaný bod spínacieho profilu na línií č. ${line} : ${value}
+dusk_has_occured;INFO;Dusk has occured;Nastal súmrak
+dawn_has_occured;INFO;Dawn has occured;Nastal úsvit
+dimming_profile_was_successfully_received_by_node;NOTICE;Dimming profile was successfully received by node no. ${node};Stmievací profil bol úspešne prijatý nodom č. ${node}
+master_node_is_responding_again;NOTICE;Master node is responding again;Master node začal znovu odpovedať
+command_was_sent_from_terminal_interface;DEBUG;A command was sent from terminal interface;Z terminálu bol odoslaný príkaz
+master_node_is_not_responding;ALERT;Master node is not responding;Master node neodpovedá
+configuration_of_dimming_profile_to_node_failed;ALERT;Configuration of dimming profile to node no. ${node} has failed;Konfigurácia stmievacieho profilu pre node č. ${node} zlyhala
+circuit_breaker_was_turned_on_line;NOTICE;Circuit breaker was turned on - line no. ${line};Zapnutie ističa na línii č. ${line}
+circuit_breaker_was_turned_off_line;ERROR;Circuit breaker was turned off - line no. ${line};Vypnutie ističa na línií č. ${line}
+dimming_profile_was_processed_for_node;INFO;Dimming profile was processed for node no. ${node};Stmievací profil bol spracovaný pre node č. ${node}
+switching_profile_was_processed_for_line;INFO;Switching profile was processed for line no. ${line};Spínací profil bol spracovaný pre líniu č. ${line}
+thermometer_is_not_responding;WARNING;Thermometer is not responding;Teplomer neodpovedá
+thermometer_is_responding_again;NOTICE;Thermometer is responding again;Teplomer znovu odpovedá
+thermometer_sends_invalid_data;WARNING;Thermometer sends invalid data;Teplomer posiela neplatné hodnoty
+main_switch_has_been_turned_off;CRITICAL;Main switch has been turned off;Hlavný vypínač bol vypnutý
+main_switch_has_been_turned_on;NOTICE;Main switch has been turned on;Hlavný vypínač bol zapnutý
+power_supply_has_disconnected_input;ALERT;Power supply has disconnected input;Napájací zdroj nemá napätie na vstupe
+power_supply_works_correctly;NOTICE;Power supply works correctly ;Napájací zdroj pracuje správne
+battery_level_is_low;ERROR;Battery level is low;Batéria má nízku úroveň napätia
+battery_level_is_ok;NOTICE;Battery level is OK;Batéria má správnu úroveň napätia
+door_has_been_open;NOTICE;Door has been open;Dvere boli otvorené
+door_has_been_closed;NOTICE;Door has been closed;Dvere boli zatvorené
+door_has_been_open_without_permision_alarm_is_on;WARNING;Door has been open without permision - alarm is on;Dvere boli otvorené bez povolania - zapnutá siréna
+state_of_contactor_for_line;INFO;State of contactor for line no. ${line} is ${value};Stav stýkača pre líniu č. ${line} je ${value}
+local_database_is_corrupted;CRITICAL;;
+electrometer_is_not_responding;ERROR;Electrometer is not responding;Elektromer neodpovedá
+no_voltage_detected_on_phase;CRITICAL;No voltage detected on phase no. ${phase};Na fáze č. ${phase} nie je napätie
+electrometer_is_responding_again;NOTICE;Electrometer is responding again;Elektromer znovu odpovedá
+voltaga_on_phase_has_been_restored;NOTICE;Voltaga on phase no. ${phase} has been restored;Napätie na fáze č. ${phase} bolo obnovené
diff --git a/flow/show_dbdata.js b/flow/show_dbdata.js
deleted file mode 100644
index 1e23ff7..0000000
--- a/flow/show_dbdata.js
+++ /dev/null
@@ -1,243 +0,0 @@
-exports.id = 'showdb';
-exports.title = 'Show db data';
-exports.group = 'Worksys';
-exports.color = '#888600';
-exports.version = '1.0.2';
-exports.icon = 'sign-out';
-exports.input = 8;
-exports.output = 1;
-
-const { exec } = require('child_process');
-
-exports.install = function(instance) {
-
- instance.on("0", _ => {
- instance.send(0, FLOW.GLOBALS.settings);
- })
- instance.on("1", _ => {
- instance.send(0, FLOW.GLOBALS.relaysData);
- })
- instance.on("2", _ => {
- instance.send(0, FLOW.GLOBALS.nodesData);
- })
- instance.on("3", _ => {
- instance.send(0, FLOW.GLOBALS.pinsData);
- })
- instance.on("4", _ => {
- instance.send(0, { rpcSwitchOffLine, rpcSetNodeDimming, rpcLineProfile, rpcNodeProfile, sunCalcExample, dataFromTerminalBroadcast })
- })
- instance.on("5", _ => {
- exec("sudo tail -n 25 monitor.txt", (err, stdout, stderr) => {
- if (err || stderr) instance.send(0, { err, stderr });
- else instance.send(0, stdout);
- })
- })
- instance.on("6", _ => {
- exec("sudo tail -n 25 err.txt", (err, stdout, stderr) => {
- if (err || stderr) instance.send(0, { err, stderr });
- else instance.send(0, stdout);
- })
- })
- instance.on("7", _ => {
- instance.send(0, FLOW.deviceStatus);
- })
-};
-
-
-const rpcSwitchOffLine =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 8,
- "method": "set_command",
- "params": {
- "entities": [
- {
- "entity_type": "edb_line",
- "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
- }
- ],
- "command": "switch",
- "payload": {
- "value": false
- }
- }
- }
- }
-}
-
-const rpcSetNodeDimming =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 10,
- "method": "set_command",
- "params": {
- "entities": [
- {
- "entity_type": "street_luminaire",
- "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
- }
- ],
- "command": "dimming",
- "payload": {
- "value": 5
- }
- }
- }
- }
-}
-
-const rpcLineProfile =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 9,
- "method": "set_profile",
- "params": {
- "entities": [
- {
- "entity_type": "edb_line",
- "tb_name": "MgnK93rkoAazbqdQ4yB2Q0yZ1YXGx6pmwBeVEP2O"
- }
- ],
- "payload": {
- "intervals": [
- {
- "value": 0,
- "end_time": "20:00",
- "start_time": "13:00"
- },
- {
- "value": 1,
- "end_time": "05:30",
- "start_time": "20:00"
- },
- {
- "value": 0,
- "end_time": "13:00",
- "start_time": "05:30"
- }
- ],
- "astro_clock": true,
- "dawn_lux_sensor": false,
- "dusk_lux_sensor": false,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 0,
- "dusk_astro_clock_offset": 0,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
- }
- }
- }
- }
-}
-
-
-const rpcNodeProfile =
-{
- "topic": "v1/gateway/rpc",
- "content": {
- "device": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV",
- "data": {
- "id": 11,
- "method": "set_profile",
- "params": {
- "entities": [
- {
- "entity_type": "street_luminaire",
- "tb_name": "jbN4q7JPZmexgdnz2yKbWdDYAWwO0Q3BMX6ERLoV"
- }
- ],
- "payload": {
- "intervals": [
- {
- "cct": 3000,
- "value": 0,
- "end_time": "17:50",
- "start_time": "13:00"
- },
- {
- "cct": 3000,
- "value": 100,
- "end_time": "21:30",
- "start_time": "17:50"
- },
- {
- "cct": 3000,
- "value": 0,
- "end_time": "13:00",
- "start_time": "07:10"
- },
- {
- "cct": 3000,
- "value": 50,
- "end_time": "00:00",
- "start_time": "21:30"
- },
- {
- "cct": 3000,
- "value": 10,
- "end_time": "04:30",
- "start_time": "00:00"
- },
- {
- "cct": 3000,
- "value": 100,
- "end_time": "07:10",
- "start_time": "04:30"
- }
- ],
- "astro_clock": true,
- "dawn_lux_sensor": false,
- "dusk_lux_sensor": false,
- "dawn_lux_sensor_value": 5,
- "dusk_lux_sensor_value": 5,
- "dawn_astro_clock_offset": 30,
- "dusk_astro_clock_offset": 20,
- "dawn_lux_sensor_time_window": 30,
- "dusk_lux_sensor_time_window": 30,
- "dawn_astro_clock_time_window": 60,
- "dusk_astro_clock_time_window": 60
- }
- }
- }
- }
-}
-
-const sunCalcExample = {
- dusk_no_offset: '20:18',
- dawn_no_offset: '05:19',
- dusk: '20:18',
- dusk_hours: 20,
- dusk_minutes: 18,
- dawn: '05:19',
- dawn_hours: 5,
- dawn_minutes: 19,
- dusk_time: 1715278688962,
- dawn_time: 1715224744357,
- dusk_astro_clock_offset: 0,
- dawn_astro_clock_offset: 0
-}
-
-
-const dataFromTerminalBroadcast = {
- address: 4294967295,
- byte1: 0,
- byte2: 0,
- byte3: 0,
- byte4: 96,
- name: "Time Schedule settings",
- recipient: 2,
- register: 8,
- rw: 1
-}
diff --git a/flow/slack_connector.js b/flow/slack_connector.js
new file mode 100644
index 0000000..8c073a6
--- /dev/null
+++ b/flow/slack_connector.js
@@ -0,0 +1,124 @@
+exports.id = 'slack_connector';
+exports.title = 'Slack_Connector';
+exports.version = '1.0.0';
+exports.group = 'Worksys';
+exports.color = '#888600';
+exports.input = 1;
+exports.output = 1;
+exports.click = false;
+exports.author = 'Jakub Klena';
+exports.icon = 'sign-out';
+exports.options = { slack_channel: "C071KN2Q8SK", api_key: "", bot_name: "Flow DEMO", bot_icon: ":totaljs:" };
+// Slack channel - where to post the messages, can be name like "backend-alerts"
+// Bot Name - Name of the "user" that will post these messages, it should be based on which server it is running on.
+// Bot Icon - We can use any slack icon (even custom ones uploaded by us) as the "user" profile picture
+
+exports.html = `
`;
+
+exports.readme = `Sends any string received on input to Slack Channel.`;
+
+var log4js = require("log4js");
+var path = require('path');
+
+log4js.configure({
+ appenders: {
+ errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
+ monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
+ console: { type: 'console' }
+ },
+ categories: {
+ errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
+ monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
+ //another: { appenders: ['console'], level: 'trace' },
+ default: { appenders: ['console'], level: 'trace' }
+ }
+});
+
+const errLogger = log4js.getLogger("errLogs");
+const logger = log4js.getLogger();
+const monitor = log4js.getLogger("monitorLogs");
+
+exports.install = function(instance) {
+ var can = false;
+
+ process.on('uncaughtException', function (err) {
+ errLogger.error('uncaughtException:', err.message);
+ errLogger.error(err.stack);
+ instance.error(err);
+ });
+
+ instance.on('data', function(data) {
+ if (!can) return;
+
+ let str = String(data.data); // Ensuring data get converted to string
+ let message = {
+ 'channel': instance.options.slack_channel,
+ 'username': instance.options.bot_name,
+ 'icon_emoji': instance.options.bot_icon,
+ 'text': str
+ };
+ let headers = {
+ 'Content-type': `application/json`,
+ 'Authorization': `Bearer ${instance.options.api_key}`
+ };
+
+ if (F.is4) {
+ let opt = {
+ 'method': 'post',
+ 'url': 'https://slack.com/api/chat.postMessage',
+ 'headers': headers,
+ 'body': JSON.stringify(message),
+ 'type': 'json',
+ 'callback': function(err, response) {
+ if (response && !err) {
+ var msg = { data: response.body, status: response.status, headers: response.headers, host: response.host, cookies: response.cookies };
+ instance.send2(msg);
+ } else if (err) {
+ errLogger.error('Slack post failed - err:', err, '\n - response was:', response);
+ instance.error(err, response);
+ }
+ }
+ };
+ REQUEST(opt);
+
+ } else {
+ U.request('https://slack.com/api/chat.postMessage', ['json', 'post'], JSON.stringify(message), function(err, data, status, headers, host) {
+ if (response && !err) {
+ response.data = { data: data, status: status, headers: headers, host: host };
+ instance.send2(response);
+ } else if (err) {
+ errLogger.error('Slack post failed - err:', err, '\n - response was:', response);
+ instance.error(err, response);
+ }
+ }, null, headers);
+ }
+ });
+
+ instance.reconfigure = function() {
+ var options = instance.options;
+ can = options.slack_channel && options.bot_name && options.bot_icon && options.api_key ? true : false;
+ instance.status(can ? '' : 'Not configured', can ? undefined : 'red');
+ };
+
+ instance.on('options', instance.reconfigure);
+ instance.reconfigure();
+}
diff --git a/flow/slack_filter.js b/flow/slack_filter.js
index 6b2d2a5..a27c9e1 100644
--- a/flow/slack_filter.js
+++ b/flow/slack_filter.js
@@ -7,10 +7,13 @@ exports.output = 1;
exports.author = 'Jakub Klena';
exports.icon = 'plug';
exports.version = '1.0.8';
-exports.options = { 'name': '', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes': '["is responding again"]', 'tag_on_include': '[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel': '' };
+exports.options = { 'name':'', 'types': '["emergency", "critical", "error", "alert"]', 'message_includes':'["is responding again"]', 'tag_on_include':'[{"user_id":"U072JE5JUQG", "includes":["Electrometer", "Twilight sensor"]}]', 'slack_channel':'' };
exports.html = `
+
+
@(Name of this server)
+
@(Slack channel to receive the alerts)
@@ -37,7 +40,7 @@ exports.install = function(instance) {
if (!running) return;
let value = response.data;
if (typeof value !== 'object') return;
-
+
let can = false
var k = Object.keys(value);
var interested = JSON.parse(instance.options.types);
@@ -57,11 +60,11 @@ exports.install = function(instance) {
let icon = ':totaljs:';
let type = value[k[0]][0]['values']['_event']['type'];
let source = value[k[0]][0]['values']['_event']['source']['func'];
- let message = value[k[0]][0]['values']['_event']['message']['en'];
+ let message = value[k[0]][0]['values']['_event']['message'];
let message_data = value[k[0]][0]['values']['_event']['message_data'];
let tag = '';
- switch (type) {
+ switch(type){
case 'debug':
icon = ':beetle:';
break;
@@ -89,15 +92,15 @@ exports.install = function(instance) {
}
// Check if this message includes one of the strings we are watching for
- for (const msg of msg_incl) {
- if (message.includes(msg)) {
+ for (const msg of msg_incl){
+ if (message.includes(msg)){
if (msg == 'is responding again') icon = ':large_green_circle:';
can = true;
break;
}
}
// Check if message is one of the types we are watching for
- if (interested.includes(type)) {
+ if (interested.includes(type)){
can = true;
}
@@ -105,10 +108,10 @@ exports.install = function(instance) {
// Check for each person tags based on what the message includes
- for (const person of tags) {
- for (const msg of person.includes) {
- if (message.includes(msg)) {
- tag += '<@' + person.user_id + '> ';
+ for (const person of tags){
+ for (const msg of person.includes){
+ if (message.includes(msg)){
+ tag += '<@'+person.user_id+'> ';
break; // Break out from this person checks as they are already tagged now
}
}
@@ -116,46 +119,46 @@ exports.install = function(instance) {
// Now that all people are tagged add new line symbol
if (tag != '') tag += '\n';
- let send_data = tag + instance.options.name + ' ' + type.toUpperCase() + '\n*Source*: ' + source + '\n*Message*: ' + message;
+ let send_data = tag+instance.options.name+' '+type.toUpperCase()+'\n*Source*: '+source+'\n*Message*: '+message;
if (message_data) {
- send_data += '\nData: ' + message_data;
+ send_data += '\nData: '+message_data;
}
let ignore_msg = false
- if (message.includes('Configuration of dimming profile to node no')) {
- for (let i = 0; i < FLOW["savedSlackMessages"].length; i++) {
- if (FLOW["savedSlackMessages"][i].message == message) {
+ if (message.includes('Configuration of dimming profile to node no')){
+ for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
+ if (FLOW["savedSlackMessages"][i].message == message){
ignore_msg = true;
break;
}
}
- if (!ignore_msg) {
- FLOW["savedSlackMessages"].push({ message, 'dateandtime': Date.now() });
- if (timer === null) {
- timer = setTimeout(checkSavedMessages, 60 * 60000);
+ if (!ignore_msg){
+ FLOW["savedSlackMessages"].push({message, 'dateandtime': Date.now()});
+ if (timer === null){
+ timer = setTimeout(checkSavedMessages, 60*60000);
}
}
}
- if (!ignore_msg) {
- instance.send2({ 'msg': send_data, 'bot_name': instance.options.name + ' ' + type.toUpperCase(), 'bot_icon': icon, 'channel': instance.options.slack_channel });
+ if (!ignore_msg){
+ instance.send2({'msg':send_data,'bot_name':instance.options.name+' '+type.toUpperCase(),'bot_icon':icon,'channel':instance.options.slack_channel});
}
});
- function checkSavedMessages() {
+ function checkSavedMessages(){
var d = Date.now();
d = d - 86400000; // older then 24hr
var a = [];
//Remove msgs older then 24hr
- for (let i = 0; i < FLOW["savedSlackMessages"].length; i++) {
- if (FLOW["savedSlackMessages"][i].dateandtime > d) {
+ for (let i = 0; i < FLOW["savedSlackMessages"].length; i++){
+ if (FLOW["savedSlackMessages"][i].dateandtime > d){
a.push(FLOW["savedSlackMessages"][i]);
}
}
FLOW["savedSlackMessages"] = a;
if (FLOW["savedSlackMessages"].length > 0) {
- timer = setTimeout(checkSavedMessages, 60 * 60000);
+ timer = setTimeout(checkSavedMessages, 60*60000);
} else {
timer = null;
}
@@ -163,16 +166,15 @@ exports.install = function(instance) {
instance.reconfigure = function() {
try {
- if (!FLOW["savedSlackMessages"]) {
+ if (!FLOW["savedSlackMessages"]){
FLOW["savedSlackMessages"] = [];
}
- instance.options.name = FLOW.GLOBALS.settings.rvo_name;
if (instance.options.name) {
instance.status('Running');
running = true;
} else {
- instance.status('Please run options again', 'red');
+ instance.status('Please enter name', 'red');
running = false;
}
} catch (e) {
@@ -181,6 +183,5 @@ exports.install = function(instance) {
};
instance.on('options', instance.reconfigure);
- setTimeout(instance.reconfigure, 10000);
-
-};
+ instance.reconfigure();
+};
\ No newline at end of file
diff --git a/flow/thermometer.js b/flow/thermometer.js
index fc7074d..1a5714f 100644
--- a/flow/thermometer.js
+++ b/flow/thermometer.js
@@ -1,99 +1,220 @@
-exports.id = 'thermometer';
-exports.title = 'Thermometer';
-exports.group = 'Worksys';
-exports.color = '#5CB36D';
-exports.input = 1;
-exports.version = '1.0.3';
-exports.output = ["red", "white", "blue"];
-exports.icon = 'thermometer-three-quarters';
-
-exports.readme = `# Getting temperature values for RVO. In case of LM, you need device address. In case of unipi, evok sends values, in case thermometer is installed`;
-
-const { errLogger, logger, monitor } = require('./helper/logger');
-
-const SEND_TO = {
- debug: 0,
- tb: 1,
- dido_controller: 2
-}
-
-//read temperature - frequency
-let timeoutMin = 5;//minutes
-let NUMBER_OF_FAILURES_TO_SEND_ERROR = 13;
-
-exports.install = function(instance) {
-
- const { exec } = require('child_process');
- const { sendNotification } = require('./helper/notification_reporter');
-
- let startRead;
- let counter = 0;
- let rvoTbName = "";
- let temperatureAddress = "";
-
- logger.debug(exports.title, "installed");
-
- instance.on("close", function() {
- clearInterval(startRead);
- })
-
-
- const main = function() {
-
- try {
-
- if (temperatureAddress === "") throw "Thermometer: temperatureAddress is not defined";
-
- exec(`owread -C ${temperatureAddress}/temperature`, (error, stdout, stderr) => {
-
- if (!error) {
- parseData(stdout)
- return;
- }
-
- counter++;
- if (counter == NUMBER_OF_FAILURES_TO_SEND_ERROR) {
- sendNotification("Thermometer_main", rvoTbName, "thermometer_is_not_responding", {}, { "Error": error }, SEND_TO.tb, instance, "thermometer");
- monitor.info("Thermometer is not responding", error);
- }
- instance.send(SEND_TO.dido_controller, { status: "NOK-thermometer" });
- });
-
- }
- catch (err) {
- errLogger.error(exports.title, err);
- clearInterval(startRead);
- }
- }
-
- const parseData = function(data) {
-
- data = parseFloat(data);
- //logger.debug("Thermometer", data);
-
- if (isNaN(data)) {
- errLogger.error("Thermometer sends invalid data");
- return;
- }
-
- if (counter > NUMBER_OF_FAILURES_TO_SEND_ERROR) //1 hour
- {
- instance.send(SEND_TO.debug, "Thermometer - temperature data are comming again");
- sendNotification("Thermometer_parseData", rvoTbName, "thermometer_is_responding_again", {}, "", SEND_TO.tb, instance, "thermometer");
- }
-
- const values = {
- "temperature": Number(data.toFixed(2)),
- }
-
- instance.send(SEND_TO.dido_controller, { values: values });
- counter = 0;
- }
-
- instance.on("data", _ => {
- temperatureAddress = FLOW.GLOBALS.settings.temperature_address;
- rvoTbName = FLOW.GLOBALS.settings.rvoTbName;
- startRead = setInterval(main, timeoutMin * 1000 * 60);
- setTimeout(main, 20000);
- })
-};
+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 acc3c33..794fedc 100644
--- a/flow/wsmqttpublish.js
+++ b/flow/wsmqttpublish.js
@@ -4,27 +4,30 @@ exports.group = 'MQTT';
exports.color = '#888600';
exports.version = '1.0.2';
exports.icon = 'sign-out';
-exports.input = 2;
-exports.output = 3;
+exports.input = 1;
+exports.output = ["red", "white", "blue"];
+exports.author = 'Daniel Segeš';
exports.options = { host: 'tb-stage.worksys.io', port: 1883, clientid: "", username: "" };
+exports.npm = ['mqtt'];
+
exports.html = `
-
-
-
Hostname or IP address (if not empty - setting will override db setting)
-
-
-
-
+
+
+
Hostname or IP address (if not empty - setting will override db setting)
+
+
+
+
`;
@@ -38,47 +41,79 @@ Added:
- rpc response
`;
-const { promisifyBuilder } = require('./helper/db_helper');
-const { errLogger, monitor } = require('./helper/logger');
-const fs = require('fs');
-const mqtt = require('mqtt');
-
-const SEND_TO = {
- debug: 0,
- rpcCall: 1,
- services: 2
+const instanceSendTo = {
+ debug: 0,
+ rpcCall: 1,
+ services: 2
}
+const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
+
//CONFIG
+let useLog4js = true;
let createTelemetryBackup = true;
let saveTelemetryOnError = true;//backup_on_failure overrides this value
//------------------------
+var fs = require('fs');
let rollers;
-if (createTelemetryBackup) rollers = require('streamroller');
+if(createTelemetryBackup) rollers = require('streamroller');
const noSqlFileSizeLimit = 4194304;//use 5MB - 4194304
let insertNoSqlCounter = 0;
let insertBackupNoSqlCounter = 0;
let processingData = false;
-let backup_on_failure = false;//== saveTelemetryOnError - create backup client send failure
+let backup_on_failure = false;//== saveTelemetryOnError - create backup broker send failure
let restore_from_backup = 0; //how many rows process at once?
let restore_backup_wait = 0;//wait seconds
let lastRestoreTime = 0;
-// if there is an error in client connection, flow logs to monitor.txt. Not to log messages every second, we use sendClientError variable
-let sendClientError = true;
+let errLogger;
+let logger;
+let monitor;
-process.on('uncaughtException', function(err) {
+if(useLog4js)
+{
+ var path = require('path');
+ var log4js = require("log4js");
+
+ log4js.configure({
+ appenders: {
+ errLogs: { type: 'file', filename: path.join(__dirname + "/../", 'err.txt') },
+ monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
+ console: { type: 'console' }
+ },
+ categories: {
+ errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
+ monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
+ //another: { appenders: ['console'], level: 'trace' },
+ default: { appenders: ['console'], level: 'trace' }
+ }
+ });
+
+ errLogger = log4js.getLogger("errLogs");
+ logger = log4js.getLogger();
+ monitor = log4js.getLogger("monitorLogs");
- errLogger.error('uncaughtException:', err.message)
- errLogger.error(err.stack);
+ //USAGE
+ //logger.debug("text");
+ //monitor.info('info');
+ //errLogger.error("some error");
+}
- //TODO
- //send to service
+process.on('uncaughtException', function (err) {
- //process.exit(1);
+ if(errLogger)
+ {
+ errLogger.error('uncaughtException:', err.message)
+ errLogger.error(err.stack);
+ }
+
+ //TODO
+ //send to service
+
+ //process.exit(1);
})
const nosql = NOSQL('tbdata');
@@ -87,364 +122,410 @@ const nosqlBackup = NOSQL('/backup/tbdata');
exports.install = function(instance) {
- var client;
- var opts;
- var clientReady = false;
+ var broker;
+ var opts;
+ var brokerready = false;
- // wsmqtt status for notification purposes on projects.worksys.io database
- let wsmqttName = null;
- let sendWsStatusVar = null;
- let wsmqtt_status = 'disconnected';
+ instance.on('options', loadSettings);
- function getWsmqttName(host) {
- if (host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
- else if (host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
- else if (host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
- }
+ mqtt = require('mqtt');
- function sendWsStatus() {
- instance.send(SEND_TO.services, { [wsmqttName]: wsmqtt_status });
- }
+ // wsmqtt status for notification purposes on projects.worksys.io database
+ let wsmqttName = null;
+ let sendWsStatusVar = null;
+ let wsmqtt_status = 'disconnected';
+
+ function getWsmqttName(host)
+ {
+ if(host == "tb-demo.worksys.io" || host == '192.168.252.4') return 'wsmqtt_demo';
+ else if(host == "tb-qas01.worksys.io" || host == '192.168.252.5') return 'wsmqtt_qas01';
+ else if(host == "tb-prod01.worksys.io" || host == '192.168.252.1') return 'wsmqtt_prod01';
+ }
+
+ function sendWsStatus()
+ {
+ instance.send(instanceSendTo.services, {[wsmqttName]: wsmqtt_status});
+ }
+
+ sendWsStatusVar = setInterval(sendWsStatus, 180000);
- function main() {
- if (!FLOW.dbLoaded) return;
+ //set opts according to db settings
+ async function loadSettings()
+ {
- loadSettings();
- clearInterval(sendWsStatus);
- sendWsStatusVar = setInterval(sendWsStatus, 180000);
- }
+ if(instance.options.host !== "")
+ {
+ //override settings from database
+ var o = instance.options;
+ opts = {
+ host: o.host,
+ port: o.port,
+ clientId: o.clientid,
+ username: o.username,
+ rejectUnauthorized: false,
+ resubscribe: false
+ };
- //set opts according to db settings
- function loadSettings() {
+ wsmqttName = getWsmqttName(o.host);
- if (instance.options.host !== "") {
- //override settings from database
- var o = instance.options;
- opts = {
- host: o.host,
- port: o.port,
- clientId: o.clientid,
- username: o.username,
- rejectUnauthorized: false,
- resubscribe: false
- };
+ console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
+ }
+ else
+ {
+
+ const dbSettings = TABLE("settings");
+ let responseSettings = await promisifyBuilder(dbSettings.find());
+
+ backup_on_failure = responseSettings[0]["backup_on_failure"];
+ saveTelemetryOnError = backup_on_failure;
+
+ restore_from_backup = responseSettings[0]["restore_from_backup"];
+ restore_backup_wait = responseSettings[0]["restore_backup_wait"];
- wsmqttName = getWsmqttName(o.host);
+ let mqtt_host = responseSettings[0]["mqtt_host"];
+ let mqtt_clientid = responseSettings[0]["mqtt_clientid"];
+ let mqtt_username = responseSettings[0]["mqtt_username"];
+ let mqtt_port = responseSettings[0]["mqtt_port"];
- console.log("wsmqttpublich -> loadSettings from instance.options", instance.options);
- }
- else {
+ console.log("wsmqttpublich -> loadSettings from db", responseSettings[0]);
- const SETTINGS = FLOW.GLOBALS.settings;
- backup_on_failure = SETTINGS.backup_on_failure;
- saveTelemetryOnError = backup_on_failure;
+ opts = {
+ host: mqtt_host,
+ port: mqtt_port,
+ keepalive: 10,
+ clientId: mqtt_clientid,
+ username: mqtt_username,
+ rejectUnauthorized: false,
+ resubscribe: false
+ };
- restore_from_backup = SETTINGS.restore_from_backup;
- restore_backup_wait = SETTINGS.restore_backup_wait;
+ wsmqttName = getWsmqttName(mqtt_host);
+ }
- let mqtt_host = SETTINGS.mqtt_host;
- let mqtt_clientid = SETTINGS.mqtt_clientid;
- let mqtt_username = SETTINGS.mqtt_username;
- let mqtt_port = SETTINGS.mqtt_port;
+ connectToTbServer();
+ }
- opts = {
- host: mqtt_host,
- port: mqtt_port,
- keepalive: 10,
- clientId: mqtt_clientid,
- username: mqtt_username,
- rejectUnauthorized: false,
- resubscribe: false,
- };
+ function connectToTbServer()
+ {
+ var url = "mqtt://" + opts.host + ":" + opts.port;
+ console.log("MQTT URL: ", url);
- wsmqttName = getWsmqttName(mqtt_host);
- }
+ broker = mqtt.connect(url, opts);
- connectToTbServer();
- }
+ broker.on('connect', function() {
+ instance.status("Connected", "green");
+ monitor.info("MQTT broker connected");
- function connectToTbServer() {
- var url = "mqtt://" + opts.host + ":" + opts.port;
- console.log("MQTT URL: ", url);
+ brokerready = true;
+ FLOW.OMS_brokerready = brokerready;
+ wsmqtt_status = 'connected';
+ });
- client = mqtt.connect(url, opts);
+ broker.on('reconnect', function() {
+ instance.status("Reconnecting", "yellow");
+ brokerready = false;
- client.on('connect', function() {
- instance.status("Connected", "green");
- //monitor.info("MQTT client connected");
+ FLOW.OMS_brokerready = brokerready;
+ });
- sendClientError = true;
- clientReady = true;
- wsmqtt_status = 'connected';
- });
+ broker.on('message', function(topic, message) {
+ // message is type of buffer
+ message = message.toString();
+ if (message[0] === '{') {
+ TRY(function() {
- client.on('reconnect', function() {
- instance.status("Reconnecting", "yellow");
- clientReady = false;
- });
+ message = JSON.parse(message);
+ if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
+ broker.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, {qos:1});
+ instance.send(instanceSendTo.rpcCall, {"device": message.device, "id": message.data.id, "RPC response": {"success": true}});
+ }
- client.on('message', function(topic, message) {
- // message is type of buffer
- message = message.toString();
- if (message[0] === '{') {
+ }, () => instance.debug('MQTT: Error parsing data', message));
+ }
- try {
- message = JSON.parse(message);
- if (message.hasOwnProperty("device") && message.hasOwnProperty("data") && message.data.hasOwnProperty("id")) {
- client.publish(topic, `{"device": ${message.device}, "id": ${message.data.id}, "data": {"success": true}}`, { qos: 1 });
- instance.send(SEND_TO.rpcCall, { "device": message.device, "id": message.data.id, "RPC response": { "success": true } });
- }
+ instance.send(instanceSendTo.rpcCall, {"topic":topic, "content":message });
+ });
- } catch (e) {
- console.log('MQTT: Error parsing data', e);
- }
- }
+ broker.on('close', function(err) {
+ brokerready = false;
+ FLOW.OMS_brokerready = brokerready;
+ wsmqtt_status = 'disconnected';
- instance.send(SEND_TO.rpcCall, { "topic": topic, "content": message });
- });
+ 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('close', function() {
- clientReady = false;
- wsmqtt_status = 'disconnected';
+ broker.reconnect();
+ });
- instance.status("Disconnected", "red");
- instance.send(SEND_TO.debug, { "message": "Client CLOSE signal received !" });
- });
+ 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);
- client.on('error', function(err) {
- instance.status("Err: " + err.code, "red");
- instance.send(SEND_TO.debug, { "message": "Client ERROR signal received !", "error": err, "opt": opts });
- if (sendClientError) {
- monitor.info('MQTT client error', err);
- sendClientError = false;
- }
- clientReady = false;
- wsmqtt_status = 'disconnected';
- });
+ brokerready = false;
+ FLOW.OMS_brokerready = brokerready;
+ wsmqtt_status = 'disconnected';
- }
+ });
+ }
- instance.on("0", _ => {
- main();
- })
+ instance.on('data', function(data) {
+ if (brokerready)
+ {
+ //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();
+ }
+
+ }
- instance.on('1', function(data) {
+ if (brokerready)
+ {
+ let stringifiedJson = JSON.stringify(data.data);
+ broker.publish("v1/gateway/telemetry", stringifiedJson, {qos: 1});
- if (clientReady) {
- //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();
- }
+ //backup telemetry
+ if(createTelemetryBackup)
+ {
+ data.data.id = UID();
+ nosqlBackup.insert(data.data);
- let stringifiedJson = JSON.stringify(data.data);
- client.publish("v1/gateway/telemetry", stringifiedJson, { qos: 1 });
+ 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();
- //backup telemetry
- if (createTelemetryBackup) {
- data.data.id = UID();
- nosqlBackup.insert(data.data);
+ insertBackupNoSqlCounter = 0;
+ }
+ }
+
+ }
+ else
+ {
- 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();
+ if(logger) logger.debug("Broker unavailable. Data not sent !", data.data);
+ instance.send(instanceSendTo.debug, {"message":"Broker unavailable. Data not sent !", "data": data.data });
- insertBackupNoSqlCounter = 0;
- }
- }
+ if(saveTelemetryOnError)
+ {
+ //create new file from tbdata.nosql, if file size exceeds given limit, and clear tbdata.nosql
+ makeBackupFromDbFile();
- }
- else {
- //logger.debug("Client unavailable. Data not sent !", JSON.stringify(data.data));
- instance.send(SEND_TO.debug, { "message": "Client unavailable. Data not sent !", "data": data.data });
+ //write to tb
+ data.data.id = UID();
+ nosql.insert(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 (clientReady) {
- client.end();
- clearInterval(sendWsStatusVar);
- }
- };
+ if (brokerready){
+ broker.end();
+ clearInterval(sendWsStatusVar);
+ }
+ };
+
+
+ function getDbBackupFileCounter(type)
+ {
+ var files = fs.readdirSync(__dirname + "/../databases");
+
+ let counter = 0;
+ for(var i = 0; i < files.length; i++)
+ {
+
+ if(files[i] == "tbdata.nosql") continue;
+
+ if(files[i].endsWith(".nosql"))
+ {
+
+ let pos = files[i].indexOf(".");
+ if(pos > -1)
+ {
+
+ let fileCounter = counter;
+ let firstDigit = files[i].slice(0, pos);
+
+ fileCounter = parseInt(firstDigit);
+ if (isNaN(fileCounter)) fileCounter = 0;
+ //console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
+
+ if(type == "max")
+ {
+ if(fileCounter > counter)
+ {
+ counter = fileCounter;
+ }
+ }
+ else if(type == "min")
+ {
+ if(counter == 0) counter = fileCounter;
+
+ if(fileCounter < counter)
+ {
+ counter = fileCounter;
+ }
+ }
+ }
+ }
+
+ }
+
+ if(type == "max") counter++;
+
+ return counter;
+ }
+
+ const makeBackupFromDbFile = async () => {
+
+ if(!saveTelemetryOnError) return;
+
+ //to avoid large file: tbdata.nosql
+
+ //init value is 0!
+ if(insertNoSqlCounter > 0)
+ {
+ --insertNoSqlCounter;
+ return;
+ }
+
+ insertNoSqlCounter = 100;
+
+ let source = __dirname + "/../databases/tbdata.nosql";
+
+ var stats = fs.statSync(source);
+ var fileSizeInBytes = stats.size;
+
+ if(fileSizeInBytes > noSqlFileSizeLimit)
+ {
+
+ let counter = 1;
+ counter = getDbBackupFileCounter("max");
+
+ let destination = __dirname + "/../databases/" + counter + "." + "tbdata.nosql";
+
+ //make backup file
+ fs.copyFileSync(source, destination);
+ //fs.renameSync(p, p + "." + counter);
+
+ //clear tbdata.nosql
+ fs.writeFileSync(source, "");
+ fs.truncateSync(source, 0);
+
+ }
+ }
+
+ const processDataFromDatabase = async () => {
+
+ if(restore_from_backup <= 0)
+ {
+ return;
+ }
+
+ //calculate diff
+ const now = new Date();
+ let currentTime = now.getTime();
+ let diff = currentTime - lastRestoreTime;
+
+ if( (diff / 1000) < restore_backup_wait)
+ {
+ //console.log("*********restore_backup_wait", diff, restore_backup_wait);
+ return;
+ }
+
+ processingData = true;
+
+ //get filename to process
+ let counter = getDbBackupFileCounter("min");
+
+ //we have some backup files
+ let dataBase = 'tbdata';
+
+ var nosql;
+ if(counter == 0) dataBase = 'tbdata';
+ else dataBase = counter + "." + 'tbdata';
+
+ nosql = NOSQL(dataBase);
+
+ //select all data - use limit restore_from_backup
+ let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
+
+ for(let i = 0; i < records.length; i++)
+ {
+ if (brokerready) {
+
+ let item = records[i];
+ let id = item.id;
+
+ if(id !== undefined)
+ {
+ //console.log("------------processDataFromDatabase - remove", id, dataBase, i);
+
+ try{
+
+ let o = JSON.parse(JSON.stringify(item));
+ delete o.id;
+ let message = JSON.stringify(o);
+
+ broker.publish("v1/gateway/telemetry", message, {qos:1});
+
+ //remove from database
+ await promisifyBuilder(nosql.remove().where("id", id));
+
+ } catch (error) {
+ //process error
+ console.log("processDataFromDatabase", error);
+ }
- function getDbBackupFileCounter(type) {
- var files = fs.readdirSync(__dirname + "/../databases");
+ }
+
+ }
+ else
+ {
+ processingData = false;
+ return;
+ }
+ }
- let counter = 0;
- for (var i = 0; i < files.length; i++) {
+ if(records.length > 0)
+ {
+ //clean backup file
+ if(counter > 0) nosql.clean();
+ }
- if (files[i] == "tbdata.nosql") continue;
+ //no data in db, remove
+ if(records.length == 0)
+ {
+ if(counter > 0) nosql.drop();
+ }
- if (files[i].endsWith(".nosql")) {
+ const d = new Date();
+ lastRestoreTime = d.getTime();
- let pos = files[i].indexOf(".");
- if (pos > -1) {
+ processingData = false;
- let fileCounter = counter;
- let firstDigit = files[i].slice(0, pos);
+ }
- fileCounter = parseInt(firstDigit);
- if (isNaN(fileCounter)) fileCounter = 0;
- //console.log("getDbBackupFileCounter digit:", files[i], firstDigit, fileCounter, isNaN(fileCounter), type);
+ loadSettings();
- if (type == "max") {
- if (fileCounter > counter) {
- counter = fileCounter;
- }
- }
- else if (type == "min") {
- if (counter == 0) counter = fileCounter;
-
- if (fileCounter < counter) {
- counter = fileCounter;
- }
- }
- }
- }
-
- }
-
- if (type == "max") counter++;
-
- return counter;
- }
-
- const makeBackupFromDbFile = async () => {
-
- if (!saveTelemetryOnError) return;
-
- //to avoid large file: tbdata.nosql
-
- //init value is 0!
- if (insertNoSqlCounter > 0) {
- --insertNoSqlCounter;
- return;
- }
-
- insertNoSqlCounter = 100;
-
- let source = __dirname + "/../databases/tbdata.nosql";
-
- var stats = fs.statSync(source);
- var fileSizeInBytes = stats.size;
-
- if (fileSizeInBytes > noSqlFileSizeLimit) {
-
- let counter = 1;
- counter = getDbBackupFileCounter("max");
-
- let destination = __dirname + "/../databases/" + counter + "." + "tbdata.nosql";
-
- //make backup file
- fs.copyFileSync(source, destination);
- //fs.renameSync(p, p + "." + counter);
-
- //clear tbdata.nosql
- fs.writeFileSync(source, "");
- fs.truncateSync(source, 0);
-
- }
- }
-
- const processDataFromDatabase = async () => {
-
- if (restore_from_backup <= 0) return;
-
- //calculate diff
- const now = new Date();
- let currentTime = now.getTime();
- let diff = currentTime - lastRestoreTime;
-
- if ((diff / 1000) < restore_backup_wait) {
- //console.log("*********restore_backup_wait", diff, restore_backup_wait);
- return;
- }
-
- processingData = true;
-
- //get filename to process
- let counter = getDbBackupFileCounter("min");
-
- //we have some backup files
- let dataBase = 'tbdata';
-
- var nosql;
- if (counter == 0) dataBase = 'tbdata';
- else dataBase = counter + "." + 'tbdata';
-
- nosql = NOSQL(dataBase);
-
- //select all data - use limit restore_from_backup
- let records = await promisifyBuilder(nosql.find().take(restore_from_backup));
-
- for (let i = 0; i < records.length; i++) {
- if (clientReady) {
-
- let item = records[i];
- let id = item.id;
-
- if (id !== undefined) {
- //console.log("------------processDataFromDatabase - remove", id, dataBase, i);
-
- try {
-
- let message = JSON.parse(JSON.stringify(item));
- delete message.id;
-
- client.publish("v1/gateway/telemetry", JSON.stringify(message), { qos: 1 });
-
- //remove from database
- await promisifyBuilder(nosql.remove().where("id", id));
-
- } catch (error) {
- //process error
- console.log("processDataFromDatabase", error);
- }
-
- }
-
- }
- else {
- processingData = false;
- return;
- }
- }
-
- if (records.length > 0) {
- //clean backup file
- if (counter > 0) nosql.clean();
- }
-
- //no data in db, remove
- if (records.length == 0) {
- if (counter > 0) nosql.drop();
- }
-
- const d = new Date();
- lastRestoreTime = d.getTime();
-
- processingData = false;
-
- }
-
- instance.on('options', main);
+ //instance.on('options', instance.reconfigure);
//instance.reconfigure();
};
diff --git a/package.json b/package.json
index 7f7c795..e524d7c 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,6 @@
"easy-crc": "0.0.2",
"jsmodbus": "^4.0.6",
"log4js": "^6.3.0",
- "moment": "^2.30.1",
"mqtt": "^4.2.6",
"nodemailer": "^6.9.7",
"serialport": "^9.2.8",