import argparse
import json
import logging
import re
import struct
import sys
from pathlib import Path

PYMODBUS_VERSION = "3.12.1"

try:
    from pymodbus.client import ModbusTcpClient
except ImportError:
    print(f"Error: 'pymodbus' module not found. Please install: pip3 install pymodbus=={PYMODBUS_VERSION}")
    sys.exit(1)

logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.ERROR)

DS501_SENSOR_TYPE = "DS_501_socket"
DS103_SENSOR_TYPE = "DS_103_3ch_switch"
EF5600_SENSOR_TYPE = "EF5600_DN1_electrical_fire_monitor"
AN201G_SENSOR_TYPE = "AN_201G_vibrating_wire_strain_gauge"
CONFIG_SNAPSHOT_NAME = "openwrt的配置文件iot_hub"
MODBUS_DEVICE_META_HEADER_REG_COUNT = 6
MODBUS_DEVICE_META_LAYOUT_HASH_OFFSET = 0
MODBUS_DEVICE_META_LAYOUT_HASH_REG_COUNT = 4
MODBUS_DEVICE_META_PROFILE_VERSION_OFFSET = 4
MODBUS_DEVICE_META_PROFILE_VERSION_REG_COUNT = 2  # uint32 big-endian: high word + low word
SUPPORTED_SENSOR_MODELS = {
    "AN-201G": AN201G_SENSOR_TYPE,
    "DS-501": DS501_SENSOR_TYPE,
    "DS-103": DS103_SENSOR_TYPE,
    "EF5600-DN1": EF5600_SENSOR_TYPE,
}

HELP_EXAMPLES = """Examples:
    python modbus_tcp_read.py --ip 192.168.1.10 --sensorType DS-501
    python modbus_tcp_read.py --ip 192.168.1.10 --sensorType EF5600-DN1 --attribute powerFactorTotal --attribute leakageCurrent
    python modbus_tcp_read.py --ip 192.168.1.10 --sensorType DS-103 --slaveId 2 --attribute switch1State
"""

_BUILTIN_SNAPSHOT = {'globals': {'http_port': '8070',
             'http_enable': '1',
             'auto_save': '1',
             'save_interval': '60',
             'check_interval': '5',
             'cleanup_threshold_pct': '80',
             'cleanup_delete_pct': '25',
             'sync_enable': '1',
             'sync_interval': '60',
             'default_sensor_type': 'undefine',
             'default_keep_alive_interval': '86400',
             'default_modbus_tcp_enable': '1',
             'default_modbus_tcp_port': '502',
             'default_modbus_tcp_slave_id': '2',
             'default_bacnet_bip_enable': '1',
             'default_bacnet_bip_id': '101',
             'unicast_max_retry': '1',
             'multicast_max_retry': '1',
             'bacnet_instance_number': '260001'},
 'attributes': {'powerState': {'name': 'powerState',
                               'json_key': 'powerState',
                               'data_type': 'bool',
                               'unit': 'none',
                               'readwrite': '1',
                               'description': 'Power on or off',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'BV',
                               'bacnet_unit': '95'},
                'switch': {'name': 'switch',
                           'json_key': 'switch',
                           'data_type': 'bool',
                           'unit': 'none',
                           'readwrite': '1',
                           'description': 'Socket switch on or off',
                           'modbus_enable': '1',
                           'modbus_table': 'holding',
                           'modbus_register_count': '1',
                           'modbus_mapping_mode': 'single',
                           'modbus_scale': '1',
                           'bacnet_enable': '1',
                           'bacnet_object_type': 'BV',
                           'bacnet_unit': '95'},
                'temperature': {'name': 'temperature',
                                'json_key': 'temperature',
                                'data_type': 'float',
                                'unit': 'celsius',
                                'decimal_places': '1',
                                'min_value': '-100',
                                'max_value': '500',
                                'readwrite': '0',
                                'description': 'Temperature',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '100',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '62'},
                'co2': {'name': 'co2',
                        'json_key': 'co2',
                        'data_type': 'int',
                        'unit': 'none',
                        'min_value': '0',
                        'max_value': '65535',
                        'readwrite': '0',
                        'description': 'CO2 concentration',
                        'modbus_enable': '1',
                        'modbus_table': 'holding',
                        'modbus_register_count': '1',
                        'modbus_mapping_mode': 'single',
                        'modbus_scale': '1',
                        'bacnet_enable': '1',
                        'bacnet_object_type': 'AI',
                        'bacnet_unit': '95'},
                'pm25': {'name': 'pm25',
                         'json_key': 'pm25',
                         'data_type': 'int',
                         'unit': 'none',
                         'min_value': '0',
                         'max_value': '65535',
                         'readwrite': '0',
                         'description': 'PM2.5 concentration',
                         'modbus_enable': '1',
                         'modbus_table': 'holding',
                         'modbus_register_count': '1',
                         'modbus_mapping_mode': 'single',
                         'modbus_scale': '1',
                         'bacnet_enable': '1',
                         'bacnet_object_type': 'AI',
                         'bacnet_unit': '95'},
                'formaldehyde': {'name': 'formaldehyde',
                                 'json_key': 'formaldehyde',
                                 'data_type': 'int',
                                 'unit': 'none',
                                 'min_value': '0',
                                 'max_value': '65535',
                                 'readwrite': '0',
                                 'description': 'Formaldehyde concentration',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '95'},
                'tvoc': {'name': 'tvoc',
                         'json_key': 'tvoc',
                         'data_type': 'int',
                         'unit': 'none',
                         'min_value': '0',
                         'max_value': '65535',
                         'readwrite': '0',
                         'description': 'TVOC concentration',
                         'modbus_enable': '1',
                         'modbus_table': 'holding',
                         'modbus_register_count': '1',
                         'modbus_mapping_mode': 'single',
                         'modbus_scale': '1',
                         'bacnet_enable': '1',
                         'bacnet_object_type': 'AI',
                         'bacnet_unit': '95'},
                'humidity': {'name': 'humidity',
                             'json_key': 'humidity',
                             'data_type': 'float',
                             'unit': 'percent',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '99.9',
                             'readwrite': '0',
                             'description': 'Humidity',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '100',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '98'},
                'bootVersion': {'name': 'bootVersion',
                                'json_key': 'bootVersion',
                                'data_type': 'string',
                                'unit': 'none',
                                'string_max_len': '16',
                                'readwrite': '0',
                                'description': 'Firmware U-boot Version',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '8',
                                'modbus_mapping_mode': 'string',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'CV',
                                'bacnet_unit': '95'},
                'mainVersion': {'name': 'mainVersion',
                                'json_key': 'mainVersion',
                                'data_type': 'string',
                                'unit': 'none',
                                'string_max_len': '16',
                                'readwrite': '0',
                                'description': 'Firmware Main Version',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '8',
                                'modbus_mapping_mode': 'string',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'CV',
                                'bacnet_unit': '95'},
                'appVersion': {'name': 'appVersion',
                               'json_key': 'appVersion',
                               'data_type': 'string',
                               'unit': 'none',
                               'string_max_len': '16',
                               'readwrite': '0',
                               'description': 'Firmware Application Version',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '8',
                               'modbus_mapping_mode': 'string',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'CV',
                               'bacnet_unit': '95'},
                'hardwareVersion': {'name': 'hardwareVersion',
                                    'json_key': 'hardwareVersion',
                                    'data_type': 'string',
                                    'unit': 'none',
                                    'string_max_len': '16',
                                    'readwrite': '0',
                                    'description': 'Hardware Version',
                                    'modbus_enable': '1',
                                    'modbus_table': 'holding',
                                    'modbus_register_count': '8',
                                    'modbus_mapping_mode': 'string',
                                    'modbus_scale': '1',
                                    'bacnet_enable': '1',
                                    'bacnet_object_type': 'CV',
                                    'bacnet_unit': '95'},
                'model': {'name': 'model',
                          'json_key': 'model',
                          'data_type': 'string',
                          'unit': 'none',
                          'string_max_len': '24',
                          'readwrite': '0',
                          'description': 'Product Model',
                          'modbus_enable': '1',
                          'modbus_table': 'holding',
                          'modbus_register_count': '12',
                          'modbus_mapping_mode': 'string',
                          'modbus_scale': '1',
                          'bacnet_enable': '1',
                          'bacnet_object_type': 'CV',
                          'bacnet_unit': '95'},
                'batteryVoltage': {'name': 'batteryVoltage',
                                   'json_key': 'batteryVoltage',
                                   'data_type': 'float',
                                   'unit': 'volt',
                                   'decimal_places': '2',
                                   'min_value': '0.1',
                                   'max_value': '48.0',
                                   'readwrite': '0',
                                   'description': 'Battery Voltage',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '100',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '5'},
                'batteryVoltageState': {'name': 'batteryVoltageState',
                                        'json_key': 'batteryVoltageState',
                                        'data_type': 'int',
                                        'unit': 'none',
                                        'min_value': '0',
                                        'max_value': '10',
                                        'readwrite': '0',
                                        'description': 'Battery State',
                                        'modbus_enable': '1',
                                        'modbus_table': 'holding',
                                        'modbus_register_count': '1',
                                        'modbus_mapping_mode': 'single',
                                        'modbus_scale': '1',
                                        'bacnet_enable': '1',
                                        'bacnet_object_type': 'AI',
                                        'bacnet_unit': '95'},
                'batteryLevel': {'name': 'batteryLevel',
                                 'json_key': 'batteryLevel',
                                 'data_type': 'int',
                                 'unit': 'percent',
                                 'min_value': '0',
                                 'max_value': '100',
                                 'readwrite': '0',
                                 'description': 'Battery level',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '98'},
                'online': {'name': 'online',
                           'json_key': 'online',
                           'data_type': 'bool',
                           'unit': 'none',
                           'readwrite': '0',
                           'description': 'Online Status',
                           'modbus_enable': '1',
                           'modbus_table': 'holding',
                           'modbus_register_count': '1',
                           'modbus_mapping_mode': 'single',
                           'modbus_scale': '1',
                           'bacnet_enable': '1',
                           'bacnet_object_type': 'BI',
                           'bacnet_unit': '95'},
                'lastOnlineTime': {'name': 'lastOnlineTime',
                                   'json_key': 'lastOnlineTime',
                                   'data_type': 'timestamp',
                                   'unit': 'second',
                                   'readwrite': '0',
                                   'description': 'Last Online Time (Unix timestamp)',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '73'},
                'doorState': {'name': 'doorState',
                              'json_key': 'doorState',
                              'data_type': 'int',
                              'unit': 'none',
                              'min_value': '0',
                              'max_value': '1',
                              'readwrite': '0',
                              'description': 'door open(1)/close(0)',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'BI',
                              'bacnet_unit': '95'},
                'levelValue': {'name': 'levelValue',
                               'json_key': 'levelValue',
                               'data_type': 'float',
                               'unit': 'percent',
                               'decimal_places': '1',
                               'min_value': '0',
                               'max_value': '100',
                               'readwrite': '0',
                               'description': 'liquid level percent',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '10',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AI',
                               'bacnet_unit': '98'},
                'presence': {'name': 'presence',
                             'json_key': 'presence',
                             'data_type': 'bool',
                             'unit': 'none',
                             'readwrite': '0',
                             'description': 'presence detection',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'BI',
                             'bacnet_unit': '95'},
                'distance': {'name': 'distance',
                             'json_key': 'distance',
                             'data_type': 'float',
                             'unit': 'meter',
                             'decimal_places': '2',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'Target Distance',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '100',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '31'},
                'lastPayload': {'name': 'lastPayload',
                                'json_key': 'lastPayload',
                                'data_type': 'binary',
                                'unit': 'none',
                                'readwrite': '0',
                                'description': 'Last Payload Data',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '130',
                                'modbus_mapping_mode': 'binary',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'CV',
                                'bacnet_unit': '95'},
                'lastPayloadLen': {'name': 'lastPayloadLen',
                                   'json_key': 'lastPayloadLen',
                                   'data_type': 'int',
                                   'unit': 'none',
                                   'min_value': '0',
                                   'max_value': '256',
                                   'description': 'Last Payload Length',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '95'},
                'lastFport': {'name': 'lastFport',
                              'json_key': 'lastFport',
                              'data_type': 'int',
                              'unit': 'none',
                              'min_value': '0',
                              'max_value': '256',
                              'description': 'Last FPort Used',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'tamper': {'name': 'tamper',
                           'json_key': 'tamper',
                           'data_type': 'int',
                           'unit': 'none',
                           'min_value': '0',
                           'max_value': '2',
                           'description': 'Tamper Detection',
                           'modbus_enable': '1',
                           'modbus_table': 'holding',
                           'modbus_register_count': '1',
                           'modbus_mapping_mode': 'single',
                           'modbus_scale': '1',
                           'bacnet_enable': '1',
                           'bacnet_object_type': 'AI',
                           'bacnet_unit': '95'},
                'tamperEvent': {'name': 'tamperEvent',
                                'json_key': 'tamperEvent',
                                'data_type': 'int',
                                'unit': 'none',
                                'min_value': '0',
                                'max_value': '2',
                                'description': 'Tamper Detection Event',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '95'},
                'infraredEvent': {'name': 'infraredEvent',
                                  'json_key': 'infraredEvent',
                                  'data_type': 'int',
                                  'unit': 'none',
                                  'readwrite': '0',
                                  'min_value': '0',
                                  'max_value': '255',
                                  'description': 'Infrared detection event code',
                                  'modbus_enable': '1',
                                  'modbus_table': 'holding',
                                  'modbus_register_count': '1',
                                  'modbus_mapping_mode': 'single',
                                  'modbus_scale': '1',
                                  'bacnet_enable': '1',
                                  'bacnet_object_type': 'AI',
                                  'bacnet_unit': '95'},
                'temperatureState': {'name': 'temperatureState',
                                     'json_key': 'temperatureState',
                                     'data_type': 'int',
                                     'unit': 'none',
                                     'min_value': '0',
                                     'max_value': '2',
                                     'readwrite': '0',
                                     'description': 'Temperature State',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '95'},
                'humidityState': {'name': 'humidityState',
                                  'json_key': 'humidityState',
                                  'data_type': 'int',
                                  'unit': 'none',
                                  'min_value': '0',
                                  'max_value': '2',
                                  'readwrite': '0',
                                  'description': 'Humidity State',
                                  'modbus_enable': '1',
                                  'modbus_table': 'holding',
                                  'modbus_register_count': '1',
                                  'modbus_mapping_mode': 'single',
                                  'modbus_scale': '1',
                                  'bacnet_enable': '1',
                                  'bacnet_object_type': 'AI',
                                  'bacnet_unit': '95'},
                'snr': {'name': 'snr',
                        'json_key': 'snr',
                        'data_type': 'int',
                        'unit': 'none',
                        'min_value': '-128',
                        'max_value': '128',
                        'readwrite': '0',
                        'description': 'SNR (dB)',
                        'modbus_enable': '1',
                        'modbus_table': 'holding',
                        'modbus_register_count': '1',
                        'modbus_mapping_mode': 'single',
                        'modbus_scale': '1',
                        'bacnet_enable': '1',
                        'bacnet_object_type': 'AI',
                        'bacnet_unit': '95'},
                'ef5600CommandCode': {'name': 'ef5600CommandCode',
                                      'json_key': 'ef5600CommandCode',
                                      'data_type': 'int',
                                      'unit': 'none',
                                      'min_value': '0',
                                      'max_value': '255',
                                      'readwrite': '1',
                                      'description': 'EF5600 Command Code',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'AV',
                                      'bacnet_unit': '95'},
                'ef5600SettingAddress': {'name': 'ef5600SettingAddress',
                                         'json_key': 'ef5600SettingAddress',
                                         'data_type': 'int',
                                         'unit': 'none',
                                         'min_value': '0',
                                         'max_value': '65535',
                                         'readwrite': '1',
                                         'description': 'EF5600 Setting Address',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '1',
                                         'modbus_mapping_mode': 'single',
                                         'modbus_scale': '1',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AV',
                                         'bacnet_unit': '95'},
                'ef5600SettingValueHigh': {'name': 'ef5600SettingValueHigh',
                                           'json_key': 'ef5600SettingValueHigh',
                                           'data_type': 'int',
                                           'unit': 'none',
                                           'min_value': '0',
                                           'max_value': '255',
                                           'readwrite': '1',
                                           'description': 'EF5600 Setting Value High Byte',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'AV',
                                           'bacnet_unit': '95'},
                'ef5600SettingValueLow': {'name': 'ef5600SettingValueLow',
                                          'json_key': 'ef5600SettingValueLow',
                                          'data_type': 'int',
                                          'unit': 'none',
                                          'min_value': '0',
                                          'max_value': '255',
                                          'readwrite': '1',
                                          'description': 'EF5600 Setting Value Low Byte',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '1',
                                          'modbus_mapping_mode': 'single',
                                          'modbus_scale': '1',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'AV',
                                          'bacnet_unit': '95'},
                'rssi': {'name': 'rssi',
                         'json_key': 'rssi',
                         'data_type': 'int',
                         'unit': 'none',
                         'min_value': '-128',
                         'max_value': '128',
                         'readwrite': '0',
                         'description': 'RSSI (dBm)',
                         'modbus_enable': '1',
                         'modbus_table': 'holding',
                         'modbus_register_count': '1',
                         'modbus_mapping_mode': 'single',
                         'modbus_scale': '1',
                         'bacnet_enable': '1',
                         'bacnet_object_type': 'AI',
                         'bacnet_unit': '95'},
                'setTemperature': {'name': 'setTemperature',
                                   'json_key': 'setTemperature',
                                   'data_type': 'float',
                                   'unit': 'celsius',
                                   'decimal_places': '1',
                                   'min_value': '10',
                                   'max_value': '35',
                                   'readwrite': '1',
                                   'description': 'Set Temperature',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '100',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AV',
                                   'bacnet_unit': '62'},
                'workMode': {'name': 'workMode',
                             'json_key': 'workMode',
                             'data_type': 'int',
                             'unit': 'none',
                             'min_value': '0',
                             'max_value': '3',
                             'readwrite': '1',
                             'description': 'Work Mode (0:auto, 1:cool, 2:heat, 3:vent)',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AV',
                             'bacnet_unit': '95'},
                'fanSpeed': {'name': 'fanSpeed',
                             'json_key': 'fanSpeed',
                             'data_type': 'int',
                             'unit': 'none',
                             'min_value': '0',
                             'max_value': '4',
                             'readwrite': '1',
                             'description': 'Fan Speed (0:off, 1:low, 2:mid, 3:high, 4:auto)',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AV',
                             'bacnet_unit': '95'},
                'keyLockState': {'name': 'keyLockState',
                                 'json_key': 'keyLockState',
                                 'data_type': 'int',
                                 'unit': 'none',
                                 'min_value': '0',
                                 'max_value': '1',
                                 'readwrite': '1',
                                 'description': 'Key Lock State (0:unlocked, 1:locked)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BV',
                                 'bacnet_unit': '95'},
                'valveState': {'name': 'valveState',
                               'json_key': 'valveState',
                               'data_type': 'int',
                               'unit': 'none',
                               'min_value': '0',
                               'max_value': '1',
                               'readwrite': '0',
                               'description': 'Valve State (0:closed, 1:open)',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'BI',
                               'bacnet_unit': '95'},
                'signalStrength': {'name': 'signalStrength',
                                   'json_key': 'signalStrength',
                                   'data_type': 'int',
                                   'unit': 'none',
                                   'min_value': '0',
                                   'max_value': '3',
                                   'readwrite': '1',
                                   'description': 'Wireless Signal Strength (0:offline, 1:poor, 2:good, 3:excellent)',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '95'},
                'cumulativeOnTime': {'name': 'cumulativeOnTime',
                                     'json_key': 'cumulativeOnTime',
                                     'data_type': 'int',
                                     'unit': 'minute',
                                     'min_value': '0',
                                     'max_value': '999999',
                                     'readwrite': '0',
                                     'description': 'Cumulative Power-On Time',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '10',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '73'},
                'cumulativeValveOpenTime': {'name': 'cumulativeValveOpenTime',
                                            'json_key': 'cumulativeValveOpenTime',
                                            'data_type': 'int',
                                            'unit': 'minute',
                                            'min_value': '0',
                                            'max_value': '999999',
                                            'readwrite': '0',
                                            'description': 'Cumulative Valve Open Time',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '10',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'AI',
                                            'bacnet_unit': '73'},
                'voltage': {'name': 'voltage',
                            'json_key': 'voltage',
                            'data_type': 'float',
                            'unit': 'volt',
                            'decimal_places': '1',
                            'min_value': '0',
                            'max_value': '300',
                            'readwrite': '0',
                            'description': 'Voltage (RMS)',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '10',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '5'},
                'current': {'name': 'current',
                            'json_key': 'current',
                            'data_type': 'float',
                            'unit': 'ampere',
                            'decimal_places': '2',
                            'min_value': '0',
                            'max_value': '20',
                            'readwrite': '0',
                            'description': 'Current (RMS)',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '100',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '8'},
                'activePower': {'name': 'activePower',
                                'json_key': 'activePower',
                                'data_type': 'float',
                                'unit': 'watt',
                                'decimal_places': '2',
                                'min_value': '0',
                                'max_value': '3500',
                                'readwrite': '0',
                                'description': 'Active Power',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '100',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '29'},
                'energy': {'name': 'energy',
                           'json_key': 'energy',
                           'data_type': 'float',
                           'unit': 'kilowatt_hour',
                           'decimal_places': '2',
                           'min_value': '0',
                           'max_value': '999999',
                           'readwrite': '0',
                           'description': 'Energy Consumption',
                           'modbus_enable': '1',
                           'modbus_table': 'holding',
                           'modbus_register_count': '2',
                           'modbus_mapping_mode': 'big_endian',
                           'modbus_scale': '100',
                           'bacnet_enable': '1',
                           'bacnet_object_type': 'AI',
                           'bacnet_unit': '30'},
                'lockState': {'name': 'lockState',
                              'json_key': 'lockState',
                              'data_type': 'int',
                              'unit': 'none',
                              'min_value': '0',
                              'max_value': '1',
                              'readwrite': '1',
                              'description': 'Socket Lock State (0:unlocked, 1:locked)',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'BV',
                              'bacnet_unit': '95'},
                'timerCloseEnabled': {'name': 'timerCloseEnabled',
                                      'json_key': 'timerCloseEnabled',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Timer Close Enabled',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'timerOpenEnabled': {'name': 'timerOpenEnabled',
                                     'json_key': 'timerOpenEnabled',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Timer Open Enabled',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'timerLockEnabled': {'name': 'timerLockEnabled',
                                     'json_key': 'timerLockEnabled',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Timer Lock Enabled',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'timerUnlockEnabled': {'name': 'timerUnlockEnabled',
                                       'json_key': 'timerUnlockEnabled',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Timer Unlock Enabled',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'waterStatus': {'name': 'waterStatus',
                                'json_key': 'waterStatus',
                                'data_type': 'bool',
                                'unit': 'none',
                                'readwrite': '0',
                                'description': 'Water Leakage Status (true=water detected)',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'BI',
                                'bacnet_unit': '95'},
                'waterDuration': {'name': 'waterDuration',
                                  'json_key': 'waterDuration',
                                  'data_type': 'int',
                                  'unit': 'minute',
                                  'min_value': '0',
                                  'max_value': '65535',
                                  'readwrite': '0',
                                  'description': 'Water Leakage Duration (minutes)',
                                  'modbus_enable': '1',
                                  'modbus_table': 'holding',
                                  'modbus_register_count': '1',
                                  'modbus_mapping_mode': 'single',
                                  'modbus_scale': '1',
                                  'bacnet_enable': '1',
                                  'bacnet_object_type': 'AI',
                                  'bacnet_unit': '73'},
                'batteryLowEvent': {'name': 'batteryLowEvent',
                                    'json_key': 'batteryLowEvent',
                                    'data_type': 'bool',
                                    'unit': 'none',
                                    'readwrite': '0',
                                    'description': 'Battery Low Voltage Event',
                                    'modbus_enable': '1',
                                    'modbus_table': 'holding',
                                    'modbus_register_count': '1',
                                    'modbus_mapping_mode': 'single',
                                    'modbus_scale': '1',
                                    'bacnet_enable': '1',
                                    'bacnet_object_type': 'BI',
                                    'bacnet_unit': '95'},
                'waterEvent': {'name': 'waterEvent',
                               'json_key': 'waterEvent',
                               'data_type': 'bool',
                               'unit': 'none',
                               'readwrite': '0',
                               'description': 'Water Leakage Event',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'BI',
                               'bacnet_unit': '95'},
                'tamperStatus': {'name': 'tamperStatus',
                                 'json_key': 'tamperStatus',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '0',
                                 'description': 'Tamper Detection Status (true=tampered)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BI',
                                 'bacnet_unit': '95'},
                'doorEvent': {'name': 'doorEvent',
                              'json_key': 'doorEvent',
                              'data_type': 'int',
                              'unit': 'none',
                              'readwrite': '0',
                              'min_value': '0',
                              'max_value': '255',
                              'description': 'Door Open/Close Event',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'sosEvent': {'name': 'sosEvent',
                             'json_key': 'sosEvent',
                             'data_type': 'bool',
                             'unit': 'none',
                             'readwrite': '0',
                             'description': 'SOS Emergency Event',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'BI',
                             'bacnet_unit': '95'},
                'smokeEvent': {'name': 'smokeEvent',
                               'json_key': 'smokeEvent',
                               'data_type': 'int',
                               'unit': 'none',
                               'readwrite': '0',
                               'min_value': '0',
                               'max_value': '255',
                               'description': 'Smoke alarm event code',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AI',
                               'bacnet_unit': '95'},
                'selfCheckEvent': {'name': 'selfCheckEvent',
                                   'json_key': 'selfCheckEvent',
                                   'data_type': 'int',
                                   'unit': 'none',
                                   'readwrite': '0',
                                   'min_value': '0',
                                   'max_value': '255',
                                   'description': 'Sensor self-check event code',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '95'},
                'smokeStatus': {'name': 'smokeStatus',
                                'json_key': 'smokeStatus',
                                'data_type': 'int',
                                'unit': 'none',
                                'readwrite': '0',
                                'min_value': '0',
                                'max_value': '255',
                                'description': 'Smoke alarm status code',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '95'},
                'sosEventTime': {'name': 'sosEventTime',
                                 'json_key': 'sosEventTime',
                                 'data_type': 'timestamp',
                                 'unit': 'second',
                                 'readwrite': '0',
                                 'description': 'SOS Event Timestamp (Unix timestamp)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '73'},
                'voltageA': {'name': 'voltageA',
                             'json_key': 'voltageA',
                             'data_type': 'float',
                             'unit': 'volt',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '300',
                             'readwrite': '0',
                             'description': 'A-phase voltage',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '5'},
                'voltageB': {'name': 'voltageB',
                             'json_key': 'voltageB',
                             'data_type': 'float',
                             'unit': 'volt',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '300',
                             'readwrite': '0',
                             'description': 'B-phase voltage',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '5'},
                'voltageC': {'name': 'voltageC',
                             'json_key': 'voltageC',
                             'data_type': 'float',
                             'unit': 'volt',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '300',
                             'readwrite': '0',
                             'description': 'C-phase voltage',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '5'},
                'voltageAvg': {'name': 'voltageAvg',
                               'json_key': 'voltageAvg',
                               'data_type': 'float',
                               'unit': 'volt',
                               'decimal_places': '1',
                               'min_value': '0',
                               'max_value': '300',
                               'readwrite': '0',
                               'description': 'Average phase voltage',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '10',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AI',
                               'bacnet_unit': '5'},
                'currentA': {'name': 'currentA',
                             'json_key': 'currentA',
                             'data_type': 'float',
                             'unit': 'ampere',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'A-phase current',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '3'},
                'currentB': {'name': 'currentB',
                             'json_key': 'currentB',
                             'data_type': 'float',
                             'unit': 'ampere',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'B-phase current',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '3'},
                'currentC': {'name': 'currentC',
                             'json_key': 'currentC',
                             'data_type': 'float',
                             'unit': 'ampere',
                             'decimal_places': '1',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'C-phase current',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '10',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '3'},
                'activePowerA': {'name': 'activePowerA',
                                 'json_key': 'activePowerA',
                                 'data_type': 'float',
                                 'unit': 'watt',
                                 'decimal_places': '2',
                                 'min_value': '0',
                                 'max_value': '10000',
                                 'readwrite': '0',
                                 'description': 'A-phase active power',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '47'},
                'activePowerTotal': {'name': 'activePowerTotal',
                                     'json_key': 'activePowerTotal',
                                     'data_type': 'float',
                                     'unit': 'watt',
                                     'decimal_places': '2',
                                     'min_value': '0',
                                     'max_value': '30000',
                                     'readwrite': '0',
                                     'description': 'Total active power',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '2',
                                     'modbus_mapping_mode': 'big_endian',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '47'},
                'powerFactorTotal': {'name': 'powerFactorTotal',
                                     'json_key': 'powerFactorTotal',
                                     'data_type': 'float',
                                     'unit': 'none',
                                     'decimal_places': '3',
                                     'min_value': '-1',
                                     'max_value': '1',
                                     'readwrite': '0',
                                     'description': 'Total power factor',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '2',
                                     'modbus_mapping_mode': 'big_endian',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '95'},
                'activeEnergy': {'name': 'activeEnergy',
                                 'json_key': 'activeEnergy',
                                 'data_type': 'float',
                                 'unit': 'kilowatt_hour',
                                 'decimal_places': '2',
                                 'min_value': '0',
                                 'max_value': '999999',
                                 'readwrite': '0',
                                 'description': 'Active energy consumption',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '19'},
                'leakageCurrent': {'name': 'leakageCurrent',
                                   'json_key': 'leakageCurrent',
                                   'data_type': 'float',
                                   'unit': 'milliampere',
                                   'decimal_places': '1',
                                   'min_value': '0',
                                   'max_value': '5000',
                                   'readwrite': '0',
                                   'description': 'Leakage current',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '10',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '2'},
                'tempSensor1': {'name': 'tempSensor1',
                                'json_key': 'tempSensor1',
                                'data_type': 'float',
                                'unit': 'celsius',
                                'decimal_places': '1',
                                'min_value': '-20',
                                'max_value': '110',
                                'readwrite': '0',
                                'description': 'Temperature sensor 1',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '10',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '62'},
                'tempAvg': {'name': 'tempAvg',
                            'json_key': 'tempAvg',
                            'data_type': 'float',
                            'unit': 'celsius',
                            'decimal_places': '1',
                            'min_value': '-20',
                            'max_value': '110',
                            'readwrite': '0',
                            'description': 'Average temperature',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '10',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '62'},
                'envTemperature': {'name': 'envTemperature',
                                   'json_key': 'envTemperature',
                                   'data_type': 'float',
                                   'unit': 'celsius',
                                   'decimal_places': '1',
                                   'min_value': '-20',
                                   'max_value': '85',
                                   'readwrite': '0',
                                   'description': 'Environment temperature',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '10',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '62'},
                'envHumidity': {'name': 'envHumidity',
                                'json_key': 'envHumidity',
                                'data_type': 'float',
                                'unit': 'percent',
                                'decimal_places': '1',
                                'min_value': '0',
                                'max_value': '100',
                                'readwrite': '0',
                                'description': 'Environment humidity',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '10',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '98'},
                'electricalAlarm': {'name': 'electricalAlarm',
                                    'json_key': 'electricalAlarm',
                                    'data_type': 'bool',
                                    'unit': 'none',
                                    'readwrite': '0',
                                    'description': 'Electrical alarm active',
                                    'modbus_enable': '1',
                                    'modbus_table': 'holding',
                                    'modbus_register_count': '1',
                                    'modbus_mapping_mode': 'single',
                                    'modbus_scale': '1',
                                    'bacnet_enable': '1',
                                    'bacnet_object_type': 'BI',
                                    'bacnet_unit': '95'},
                'alarmOvercurrentA': {'name': 'alarmOvercurrentA',
                                      'json_key': 'alarmOvercurrentA',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'A-phase overcurrent alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmLeakage': {'name': 'alarmLeakage',
                                 'json_key': 'alarmLeakage',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '0',
                                 'description': 'Leakage current alarm',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BI',
                                 'bacnet_unit': '95'},
                'tiltAngle': {'name': 'tiltAngle',
                              'json_key': 'tiltAngle',
                              'data_type': 'int',
                              'unit': 'degree',
                              'min_value': '0',
                              'max_value': '360',
                              'readwrite': '0',
                              'description': 'Tilt angle in degrees',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '96'},
                'illuminance': {'name': 'illuminance',
                                'json_key': 'illuminance',
                                'data_type': 'int',
                                'unit': 'lux',
                                'min_value': '0',
                                'max_value': '100000',
                                'readwrite': '0',
                                'description': 'Light illuminance in Lux',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '2',
                                'modbus_mapping_mode': 'big_endian',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '86'},
                'liquidLevel': {'name': 'liquidLevel',
                                'json_key': 'liquidLevel',
                                'data_type': 'float',
                                'unit': 'meter',
                                'decimal_places': '2',
                                'min_value': '0',
                                'max_value': '100',
                                'readwrite': '0',
                                'description': 'Liquid level in meters',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '100',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '31'},
                'liquidLevelPercent': {'name': 'liquidLevelPercent',
                                       'json_key': 'liquidLevelPercent',
                                       'data_type': 'float',
                                       'unit': 'percent',
                                       'decimal_places': '1',
                                       'min_value': '0',
                                       'max_value': '100',
                                       'readwrite': '0',
                                       'description': 'Liquid level percentage',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '10',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AI',
                                       'bacnet_unit': '98'},
                'atmosphericPressure': {'name': 'atmosphericPressure',
                                        'json_key': 'atmosphericPressure',
                                        'data_type': 'int',
                                        'unit': 'pascal',
                                        'min_value': '80000',
                                        'max_value': '120000',
                                        'readwrite': '0',
                                        'description': 'Atmospheric pressure in Pascals',
                                        'modbus_enable': '1',
                                        'modbus_table': 'holding',
                                        'modbus_register_count': '2',
                                        'modbus_mapping_mode': 'big_endian',
                                        'modbus_scale': '1',
                                        'bacnet_enable': '1',
                                        'bacnet_object_type': 'AI',
                                        'bacnet_unit': '100'},
                'altitude': {'name': 'altitude',
                             'json_key': 'altitude',
                             'data_type': 'float',
                             'unit': 'meter',
                             'decimal_places': '1',
                             'min_value': '-1000',
                             'max_value': '10000',
                             'readwrite': '0',
                             'description': 'altitude',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '2',
                             'modbus_mapping_mode': 'big_endian',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '31'},
                'switch1State': {'name': 'switch1State',
                                 'json_key': 'switch1State',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '1',
                                 'description': 'Switch 1 state (0=off, 1=on)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BV',
                                 'bacnet_unit': '95'},
                'switch2State': {'name': 'switch2State',
                                 'json_key': 'switch2State',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '1',
                                 'description': 'Switch 2 state (0=off, 1=on)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BV',
                                 'bacnet_unit': '95'},
                'switch3State': {'name': 'switch3State',
                                 'json_key': 'switch3State',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '1',
                                 'description': 'Switch 3 state (0=off, 1=on)',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BV',
                                 'bacnet_unit': '95'},
                'alarmStatus': {'name': 'alarmStatus',
                                'json_key': 'alarmStatus',
                                'data_type': 'bool',
                                'unit': 'none',
                                'readwrite': '1',
                                'description': 'Sound & light alarm status (0=off, 1=on)',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'BV',
                                'bacnet_unit': '95'},
                'alarmDurationSeconds': {'name': 'alarmDurationSeconds',
                                         'json_key': 'alarmDurationSeconds',
                                         'data_type': 'int',
                                         'unit': 'seconds',
                                         'min_value': '0',
                                         'max_value': '65535',
                                         'readwrite': '1',
                                         'description': 'Optional auto-off delay in seconds for AN-307 alarm control',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '1',
                                         'modbus_mapping_mode': 'single',
                                         'modbus_scale': '1',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AV',
                                         'bacnet_unit': '73'},
                'vibFreqX': {'name': 'vibFreqX',
                             'json_key': 'vibFreqX',
                             'data_type': 'int',
                             'unit': 'hertz',
                             'min_value': '0',
                             'max_value': '1000',
                             'readwrite': '0',
                             'description': 'X-axis vibration frequency in Hz',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '72'},
                'vibAccelX': {'name': 'vibAccelX',
                              'json_key': 'vibAccelX',
                              'data_type': 'int',
                              'unit': 'millig',
                              'min_value': '0',
                              'max_value': '20000',
                              'readwrite': '0',
                              'description': 'X-axis acceleration in mg',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '166'},
                'vibVelX': {'name': 'vibVelX',
                            'json_key': 'vibVelX',
                            'data_type': 'float',
                            'unit': 'millimeter_per_second',
                            'decimal_places': '1',
                            'min_value': '0',
                            'max_value': '1000',
                            'readwrite': '0',
                            'description': 'X-axis velocity in mm/s',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '10',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '134'},
                'fallAlarmStatus': {'name': 'fallAlarmStatus',
                                    'json_key': 'fallAlarmStatus',
                                    'data_type': 'bool',
                                    'unit': 'none',
                                    'readwrite': '0',
                                    'description': 'Fall detection alarm status (0=no alarm, 1=alarm)',
                                    'modbus_enable': '1',
                                    'modbus_table': 'holding',
                                    'modbus_register_count': '1',
                                    'modbus_mapping_mode': 'single',
                                    'modbus_scale': '1',
                                    'bacnet_enable': '1',
                                    'bacnet_object_type': 'BI',
                                    'bacnet_unit': '95'},
                'helmetRemovalAlarmStatus': {'name': 'helmetRemovalAlarmStatus',
                                             'json_key': 'helmetRemovalAlarmStatus',
                                             'data_type': 'bool',
                                             'unit': 'none',
                                             'readwrite': '0',
                                             'description': 'Helmet removal alarm status (0=no alarm, 1=alarm)',
                                             'modbus_enable': '1',
                                             'modbus_table': 'holding',
                                             'modbus_register_count': '1',
                                             'modbus_mapping_mode': 'single',
                                             'modbus_scale': '1',
                                             'bacnet_enable': '1',
                                             'bacnet_object_type': 'BI',
                                             'bacnet_unit': '95'},
                'electricityProximityAlarmStatus': {'name': 'electricityProximityAlarmStatus',
                                                    'json_key': 'electricityProximityAlarmStatus',
                                                    'data_type': 'bool',
                                                    'unit': 'none',
                                                    'readwrite': '0',
                                                    'description': 'Proximity to electricity alarm status (0=no alarm, '
                                                                   '1=alarm)',
                                                    'modbus_enable': '1',
                                                    'modbus_table': 'holding',
                                                    'modbus_register_count': '1',
                                                    'modbus_mapping_mode': 'single',
                                                    'modbus_scale': '1',
                                                    'bacnet_enable': '1',
                                                    'bacnet_object_type': 'BI',
                                                    'bacnet_unit': '95'},
                'temperatureAlarmStatus': {'name': 'temperatureAlarmStatus',
                                           'json_key': 'temperatureAlarmStatus',
                                           'data_type': 'int',
                                           'unit': 'none',
                                           'min_value': '0',
                                           'max_value': '3',
                                           'readwrite': '0',
                                           'description': 'Temperature alarm status (0=normal, 1=too low, 2=too high, '
                                                          '3=cannot collect)',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'AI',
                                           'bacnet_unit': '95'},
                'batteryLowAlarm': {'name': 'batteryLowAlarm',
                                    'json_key': 'batteryLowAlarm',
                                    'data_type': 'bool',
                                    'unit': 'none',
                                    'readwrite': '0',
                                    'description': 'Battery low percentage alarm',
                                    'modbus_enable': '1',
                                    'modbus_table': 'holding',
                                    'modbus_register_count': '1',
                                    'modbus_mapping_mode': 'single',
                                    'modbus_scale': '1',
                                    'bacnet_enable': '1',
                                    'bacnet_object_type': 'BI',
                                    'bacnet_unit': '95'},
                'accelerationAlarm': {'name': 'accelerationAlarm',
                                      'json_key': 'accelerationAlarm',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Acceleration alarm (0=normal, 1=alarm)',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'tiltAlarm': {'name': 'tiltAlarm',
                              'json_key': 'tiltAlarm',
                              'data_type': 'bool',
                              'unit': 'none',
                              'readwrite': '0',
                              'description': 'Tilt angle alarm (0=normal, 1=alarm)',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'BI',
                              'bacnet_unit': '95'},
                'sensorAbnormal': {'name': 'sensorAbnormal',
                                   'json_key': 'sensorAbnormal',
                                   'data_type': 'bool',
                                   'unit': 'none',
                                   'readwrite': '0',
                                   'description': 'Sensor abnormal status (0=normal, 1=abnormal)',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'BI',
                                   'bacnet_unit': '95'},
                'liquidLevelStatus': {'name': 'liquidLevelStatus',
                                      'json_key': 'liquidLevelStatus',
                                      'data_type': 'int',
                                      'unit': 'none',
                                      'min_value': '0',
                                      'max_value': '2',
                                      'readwrite': '0',
                                      'description': 'Liquid level status (0=normal, 1=too low, 2=too high)',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'AI',
                                      'bacnet_unit': '95'},
                'vibrationAlarmStatus': {'name': 'vibrationAlarmStatus',
                                         'json_key': 'vibrationAlarmStatus',
                                         'data_type': 'int',
                                         'unit': 'none',
                                         'min_value': '0',
                                         'max_value': '65535',
                                         'readwrite': '0',
                                         'description': 'Vibration alarm status bitfield',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '1',
                                         'modbus_mapping_mode': 'single',
                                         'modbus_scale': '1',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AI',
                                         'bacnet_unit': '95'},
                'safetyAlarmActive': {'name': 'safetyAlarmActive',
                                      'json_key': 'safetyAlarmActive',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Any safety alarm active (0=normal, 1=alarm)',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'latitude': {'name': 'latitude',
                             'json_key': 'latitude',
                             'data_type': 'float',
                             'unit': 'degrees',
                             'decimal_places': '6',
                             'min_value': '-90',
                             'max_value': '90',
                             'readwrite': '0',
                             'description': 'GPS latitude',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '2',
                             'modbus_mapping_mode': 'big_endian',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '95'},
                'longitude': {'name': 'longitude',
                              'json_key': 'longitude',
                              'data_type': 'float',
                              'unit': 'degrees',
                              'decimal_places': '6',
                              'min_value': '-180',
                              'max_value': '180',
                              'readwrite': '0',
                              'description': 'GPS longitude',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '2',
                              'modbus_mapping_mode': 'big_endian',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'positionAccuracy': {'name': 'positionAccuracy',
                                     'json_key': 'positionAccuracy',
                                     'data_type': 'float',
                                     'unit': 'meter',
                                     'decimal_places': '2',
                                     'min_value': '0',
                                     'max_value': '1000',
                                     'readwrite': '0',
                                     'description': 'GPS position accuracy',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '2',
                                     'modbus_mapping_mode': 'big_endian',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '31'},
                'gpsAbsoluteTimestamp': {'name': 'gpsAbsoluteTimestamp',
                                         'json_key': 'gpsAbsoluteTimestamp',
                                         'data_type': 'timestamp',
                                         'unit': 'second',
                                         'readwrite': '0',
                                         'description': 'GPS absolute timestamp',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '2',
                                         'modbus_mapping_mode': 'big_endian',
                                         'modbus_scale': '1',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AI',
                                         'bacnet_unit': '73'},
                'gpsTimeValid': {'name': 'gpsTimeValid',
                                 'json_key': 'gpsTimeValid',
                                 'data_type': 'bool',
                                 'unit': 'none',
                                 'readwrite': '0',
                                 'description': 'time-valid flag',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '1',
                                 'modbus_mapping_mode': 'single',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'BI',
                                 'bacnet_unit': '95'},
                'timestamp': {'name': 'timestamp',
                              'json_key': 'timestamp',
                              'data_type': 'int',
                              'unit': 'seconds',
                              'min_value': '0',
                              'max_value': '4294967295',
                              'readwrite': '0',
                              'description': 'Unix timestamp in seconds',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '2',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'vibratingWireSensorModel': {'name': 'vibratingWireSensorModel',
                                             'json_key': 'vibratingWireSensorModel',
                                             'data_type': 'int',
                                             'unit': 'none',
                                             'min_value': '0',
                                             'max_value': '255',
                                             'readwrite': '0',
                                             'description': 'Vibrating wire sensor model code',
                                             'modbus_enable': '1',
                                             'modbus_table': 'holding',
                                             'modbus_register_count': '1',
                                             'modbus_mapping_mode': 'single',
                                             'modbus_scale': '1',
                                             'bacnet_enable': '1',
                                             'bacnet_object_type': 'AI',
                                             'bacnet_unit': '95'},
                'frequency': {'name': 'frequency',
                              'json_key': 'frequency',
                              'data_type': 'float',
                              'unit': 'hertz',
                              'decimal_places': '2',
                              'min_value': '0',
                              'max_value': '10000',
                              'readwrite': '0',
                              'description': 'Latest vibrating wire frequency in Hz',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '2',
                              'modbus_mapping_mode': 'big_endian',
                              'modbus_scale': '100',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '72'},
                'frequencyDigit': {'name': 'frequencyDigit',
                                   'json_key': 'frequencyDigit',
                                   'data_type': 'float',
                                   'unit': 'digit',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '1000000',
                                   'readwrite': '0',
                                   'description': 'Latest frequency modulus digit calculated by f^2/1000',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '100',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '95'},
                'initialFrequency': {'name': 'initialFrequency',
                                     'json_key': 'initialFrequency',
                                     'data_type': 'float',
                                     'unit': 'hertz',
                                     'decimal_places': '2',
                                     'min_value': '0',
                                     'max_value': '10000',
                                     'readwrite': '0',
                                     'description': 'Initial baseline vibrating wire frequency in Hz',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '2',
                                     'modbus_mapping_mode': 'big_endian',
                                     'modbus_scale': '100',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '72'},
                'initialFrequencyDigit': {'name': 'initialFrequencyDigit',
                                          'json_key': 'initialFrequencyDigit',
                                          'data_type': 'float',
                                          'unit': 'digit',
                                          'decimal_places': '2',
                                          'min_value': '0',
                                          'max_value': '1000000',
                                          'readwrite': '0',
                                          'description': 'Initial baseline frequency modulus digit calculated by '
                                                         'f^2/1000',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '2',
                                          'modbus_mapping_mode': 'big_endian',
                                          'modbus_scale': '100',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'AI',
                                          'bacnet_unit': '95'},
                'initialTemperature': {'name': 'initialTemperature',
                                       'json_key': 'initialTemperature',
                                       'data_type': 'float',
                                       'unit': 'celsius',
                                       'decimal_places': '1',
                                       'min_value': '-100',
                                       'max_value': '500',
                                       'readwrite': '0',
                                       'description': 'Initial baseline temperature',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '10',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AI',
                                       'bacnet_unit': '62'},
                'correctionFactor': {'name': 'correctionFactor',
                                     'json_key': 'correctionFactor',
                                     'data_type': 'float',
                                     'unit': 'none',
                                     'decimal_places': '4',
                                     'min_value': '0',
                                     'max_value': '10',
                                     'readwrite': '0',
                                     'description': 'Average correction factor C used in strain calculation, default '
                                                    '1.0',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '2',
                                     'modbus_mapping_mode': 'big_endian',
                                     'modbus_scale': '10000',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '95'},
                'steelStructureStrain': {'name': 'steelStructureStrain',
                                         'json_key': 'steelStructureStrain',
                                         'data_type': 'float',
                                         'unit': 'microstrain',
                                         'decimal_places': '2',
                                         'min_value': '-5000000',
                                         'max_value': '5000000',
                                         'readwrite': '0',
                                         'description': 'Calculated strain for surface-mounted steel structure in '
                                                        'microstrain',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '2',
                                         'modbus_mapping_mode': 'big_endian',
                                         'modbus_scale': '100',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AI',
                                         'bacnet_unit': '95'},
                'concreteStructureStrain': {'name': 'concreteStructureStrain',
                                            'json_key': 'concreteStructureStrain',
                                            'data_type': 'float',
                                            'unit': 'microstrain',
                                            'decimal_places': '2',
                                            'min_value': '-5000000',
                                            'max_value': '5000000',
                                            'readwrite': '0',
                                            'description': 'Calculated strain for surface-mounted concrete structure '
                                                           'in microstrain',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '2',
                                            'modbus_mapping_mode': 'big_endian',
                                            'modbus_scale': '100',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'AI',
                                            'bacnet_unit': '95'},
                'isHeartbeat': {'name': 'isHeartbeat',
                                'json_key': 'isHeartbeat',
                                'data_type': 'bool',
                                'unit': 'none',
                                'readwrite': '0',
                                'description': 'Heartbeat message indicator',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'BI',
                                'bacnet_unit': '95'},
                'beaconIdHex': {'name': 'beaconIdHex',
                                'json_key': 'beaconIdHex',
                                'data_type': 'string',
                                'unit': 'none',
                                'string_max_len': '32',
                                'readwrite': '0',
                                'description': 'Latest beacon identifier in hexadecimal',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '16',
                                'modbus_mapping_mode': 'string',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'CV',
                                'bacnet_unit': '95'},
                'beaconRssi': {'name': 'beaconRssi',
                               'json_key': 'beaconRssi',
                               'data_type': 'int',
                               'unit': 'none',
                               'min_value': '-120',
                               'max_value': '0',
                               'readwrite': '0',
                               'description': 'Latest beacon RSSI signal strength',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AI',
                               'bacnet_unit': '95'},
                'beaconBatteryLevel': {'name': 'beaconBatteryLevel',
                                       'json_key': 'beaconBatteryLevel',
                                       'data_type': 'int',
                                       'unit': 'percent',
                                       'min_value': '0',
                                       'max_value': '100',
                                       'readwrite': '0',
                                       'description': 'Latest beacon battery level percentage',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AI',
                                       'bacnet_unit': '98'},
                'beaconBatteryValid': {'name': 'beaconBatteryValid',
                                       'json_key': 'beaconBatteryValid',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Latest beacon battery level valid flag',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'vibFreqY': {'name': 'vibFreqY',
                             'json_key': 'vibFreqY',
                             'data_type': 'int',
                             'unit': 'hertz',
                             'min_value': '0',
                             'max_value': '1000',
                             'readwrite': '0',
                             'description': 'Y-axis vibration frequency in Hz',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '72'},
                'vibFreqZ': {'name': 'vibFreqZ',
                             'json_key': 'vibFreqZ',
                             'data_type': 'int',
                             'unit': 'hertz',
                             'min_value': '0',
                             'max_value': '1000',
                             'readwrite': '0',
                             'description': 'Z-axis vibration frequency in Hz',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '72'},
                'vibAccelY': {'name': 'vibAccelY',
                              'json_key': 'vibAccelY',
                              'data_type': 'float',
                              'unit': 'g',
                              'decimal_places': '3',
                              'min_value': '0',
                              'max_value': '100',
                              'readwrite': '0',
                              'description': 'Y-axis vibration acceleration in g',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1000',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'vibAccelZ': {'name': 'vibAccelZ',
                              'json_key': 'vibAccelZ',
                              'data_type': 'float',
                              'unit': 'g',
                              'decimal_places': '3',
                              'min_value': '0',
                              'max_value': '100',
                              'readwrite': '0',
                              'description': 'Z-axis vibration acceleration in g',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '1000',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AI',
                              'bacnet_unit': '95'},
                'vibVelY': {'name': 'vibVelY',
                            'json_key': 'vibVelY',
                            'data_type': 'float',
                            'unit': 'mm/s',
                            'decimal_places': '2',
                            'min_value': '0',
                            'max_value': '1000',
                            'readwrite': '0',
                            'description': 'Y-axis vibration velocity in mm/s',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '100',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '95'},
                'vibVelZ': {'name': 'vibVelZ',
                            'json_key': 'vibVelZ',
                            'data_type': 'float',
                            'unit': 'mm/s',
                            'decimal_places': '2',
                            'min_value': '0',
                            'max_value': '1000',
                            'readwrite': '0',
                            'description': 'Z-axis vibration velocity in mm/s',
                            'modbus_enable': '1',
                            'modbus_table': 'holding',
                            'modbus_register_count': '1',
                            'modbus_mapping_mode': 'single',
                            'modbus_scale': '100',
                            'bacnet_enable': '1',
                            'bacnet_object_type': 'AI',
                            'bacnet_unit': '95'},
                'vibDispX': {'name': 'vibDispX',
                             'json_key': 'vibDispX',
                             'data_type': 'float',
                             'unit': 'mm',
                             'decimal_places': '3',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'X-axis vibration displacement in mm',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1000',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '95'},
                'vibDispY': {'name': 'vibDispY',
                             'json_key': 'vibDispY',
                             'data_type': 'float',
                             'unit': 'mm',
                             'decimal_places': '3',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'Y-axis vibration displacement in mm',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1000',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '95'},
                'vibDispZ': {'name': 'vibDispZ',
                             'json_key': 'vibDispZ',
                             'data_type': 'float',
                             'unit': 'mm',
                             'decimal_places': '3',
                             'min_value': '0',
                             'max_value': '100',
                             'readwrite': '0',
                             'description': 'Z-axis vibration displacement in mm',
                             'modbus_enable': '1',
                             'modbus_table': 'holding',
                             'modbus_register_count': '1',
                             'modbus_mapping_mode': 'single',
                             'modbus_scale': '1000',
                             'bacnet_enable': '1',
                             'bacnet_object_type': 'AI',
                             'bacnet_unit': '95'},
                'alarmAccelX': {'name': 'alarmAccelX',
                                'json_key': 'alarmAccelX',
                                'data_type': 'float',
                                'unit': 'g',
                                'decimal_places': '3',
                                'min_value': '0',
                                'max_value': '100',
                                'readwrite': '1',
                                'description': 'X-axis acceleration alarm threshold in g',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1000',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AV',
                                'bacnet_unit': '95'},
                'alarmAccelY': {'name': 'alarmAccelY',
                                'json_key': 'alarmAccelY',
                                'data_type': 'float',
                                'unit': 'g',
                                'decimal_places': '3',
                                'min_value': '0',
                                'max_value': '100',
                                'readwrite': '1',
                                'description': 'Y-axis acceleration alarm threshold in g',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1000',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AV',
                                'bacnet_unit': '95'},
                'alarmAccelZ': {'name': 'alarmAccelZ',
                                'json_key': 'alarmAccelZ',
                                'data_type': 'float',
                                'unit': 'g',
                                'decimal_places': '3',
                                'min_value': '0',
                                'max_value': '100',
                                'readwrite': '1',
                                'description': 'Z-axis acceleration alarm threshold in g',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '1000',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AV',
                                'bacnet_unit': '95'},
                'alarmVelX': {'name': 'alarmVelX',
                              'json_key': 'alarmVelX',
                              'data_type': 'float',
                              'unit': 'mm/s',
                              'decimal_places': '2',
                              'min_value': '0',
                              'max_value': '1000',
                              'readwrite': '1',
                              'description': 'X-axis velocity alarm threshold in mm/s',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '100',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AV',
                              'bacnet_unit': '95'},
                'alarmVelY': {'name': 'alarmVelY',
                              'json_key': 'alarmVelY',
                              'data_type': 'float',
                              'unit': 'mm/s',
                              'decimal_places': '2',
                              'min_value': '0',
                              'max_value': '1000',
                              'readwrite': '1',
                              'description': 'Y-axis velocity alarm threshold in mm/s',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '100',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AV',
                              'bacnet_unit': '95'},
                'alarmVelZ': {'name': 'alarmVelZ',
                              'json_key': 'alarmVelZ',
                              'data_type': 'float',
                              'unit': 'mm/s',
                              'decimal_places': '2',
                              'min_value': '0',
                              'max_value': '1000',
                              'readwrite': '1',
                              'description': 'Z-axis velocity alarm threshold in mm/s',
                              'modbus_enable': '1',
                              'modbus_table': 'holding',
                              'modbus_register_count': '1',
                              'modbus_mapping_mode': 'single',
                              'modbus_scale': '100',
                              'bacnet_enable': '1',
                              'bacnet_object_type': 'AV',
                              'bacnet_unit': '95'},
                'alarmDispX': {'name': 'alarmDispX',
                               'json_key': 'alarmDispX',
                               'data_type': 'float',
                               'unit': 'mm',
                               'decimal_places': '3',
                               'min_value': '0',
                               'max_value': '100',
                               'readwrite': '1',
                               'description': 'X-axis displacement alarm threshold in mm',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1000',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AV',
                               'bacnet_unit': '95'},
                'alarmDispY': {'name': 'alarmDispY',
                               'json_key': 'alarmDispY',
                               'data_type': 'float',
                               'unit': 'mm',
                               'decimal_places': '3',
                               'min_value': '0',
                               'max_value': '100',
                               'readwrite': '1',
                               'description': 'Y-axis displacement alarm threshold in mm',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1000',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AV',
                               'bacnet_unit': '95'},
                'alarmDispZ': {'name': 'alarmDispZ',
                               'json_key': 'alarmDispZ',
                               'data_type': 'float',
                               'unit': 'mm',
                               'decimal_places': '3',
                               'min_value': '0',
                               'max_value': '100',
                               'readwrite': '1',
                               'description': 'Z-axis displacement alarm threshold in mm',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '1000',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AV',
                               'bacnet_unit': '95'},
                'timerOpenEnabled1': {'name': 'timerOpenEnabled1',
                                      'json_key': 'timerOpenEnabled1',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Timer open enable for channel 1',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BV',
                                      'bacnet_unit': '95'},
                'timerOpenEnabled2': {'name': 'timerOpenEnabled2',
                                      'json_key': 'timerOpenEnabled2',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Timer open enable for channel 2',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BV',
                                      'bacnet_unit': '95'},
                'timerOpenEnabled3': {'name': 'timerOpenEnabled3',
                                      'json_key': 'timerOpenEnabled3',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Timer open enable for channel 3',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BV',
                                      'bacnet_unit': '95'},
                'timerCloseEnabled1': {'name': 'timerCloseEnabled1',
                                       'json_key': 'timerCloseEnabled1',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Timer close enable for channel 1',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BV',
                                       'bacnet_unit': '95'},
                'timerCloseEnabled2': {'name': 'timerCloseEnabled2',
                                       'json_key': 'timerCloseEnabled2',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Timer close enable for channel 2',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BV',
                                       'bacnet_unit': '95'},
                'timerCloseEnabled3': {'name': 'timerCloseEnabled3',
                                       'json_key': 'timerCloseEnabled3',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Timer close enable for channel 3',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BV',
                                       'bacnet_unit': '95'},
                'temperatureEvent': {'name': 'temperatureEvent',
                                     'json_key': 'temperatureEvent',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Temperature alarm event',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'presenceEvent': {'name': 'presenceEvent',
                                  'json_key': 'presenceEvent',
                                  'data_type': 'int',
                                  'unit': 'none',
                                  'readwrite': '0',
                                  'min_value': '0',
                                  'max_value': '255',
                                  'description': 'Presence detection event code',
                                  'modbus_enable': '1',
                                  'modbus_table': 'holding',
                                  'modbus_register_count': '1',
                                  'modbus_mapping_mode': 'single',
                                  'modbus_scale': '1',
                                  'bacnet_enable': '1',
                                  'bacnet_object_type': 'AI',
                                  'bacnet_unit': '95'},
                'liquidLevelEvent': {'name': 'liquidLevelEvent',
                                     'json_key': 'liquidLevelEvent',
                                     'data_type': 'int',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'min_value': '0',
                                     'max_value': '255',
                                     'description': 'Liquid level change event code',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AI',
                                     'bacnet_unit': '95'},
                'vibrationAlarmEvent': {'name': 'vibrationAlarmEvent',
                                        'json_key': 'vibrationAlarmEvent',
                                        'data_type': 'bool',
                                        'unit': 'none',
                                        'readwrite': '0',
                                        'description': 'Vibration alarm event',
                                        'modbus_enable': '1',
                                        'modbus_table': 'holding',
                                        'modbus_register_count': '1',
                                        'modbus_mapping_mode': 'single',
                                        'modbus_scale': '1',
                                        'bacnet_enable': '1',
                                        'bacnet_object_type': 'BI',
                                        'bacnet_unit': '95'},
                'fallAlarmEvent': {'name': 'fallAlarmEvent',
                                   'json_key': 'fallAlarmEvent',
                                   'data_type': 'bool',
                                   'unit': 'none',
                                   'readwrite': '0',
                                   'description': 'Fall detection alarm event',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '1',
                                   'modbus_mapping_mode': 'single',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'BI',
                                   'bacnet_unit': '95'},
                'helmetRemovalAlarmEvent': {'name': 'helmetRemovalAlarmEvent',
                                            'json_key': 'helmetRemovalAlarmEvent',
                                            'data_type': 'bool',
                                            'unit': 'none',
                                            'readwrite': '0',
                                            'description': 'Helmet removal alarm event',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '1',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'BI',
                                            'bacnet_unit': '95'},
                'electricityProximityAlarmEvent': {'name': 'electricityProximityAlarmEvent',
                                                   'json_key': 'electricityProximityAlarmEvent',
                                                   'data_type': 'bool',
                                                   'unit': 'none',
                                                   'readwrite': '0',
                                                   'description': 'Electricity proximity alarm event',
                                                   'modbus_enable': '1',
                                                   'modbus_table': 'holding',
                                                   'modbus_register_count': '1',
                                                   'modbus_mapping_mode': 'single',
                                                   'modbus_scale': '1',
                                                   'bacnet_enable': '1',
                                                   'bacnet_object_type': 'BI',
                                                   'bacnet_unit': '95'},
                'impactAlarmEvent': {'name': 'impactAlarmEvent',
                                     'json_key': 'impactAlarmEvent',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Impact detection alarm event',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'silenceAlarmEvent': {'name': 'silenceAlarmEvent',
                                      'json_key': 'silenceAlarmEvent',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Silence alarm event',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmEventActive': {'name': 'alarmEventActive',
                                     'json_key': 'alarmEventActive',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'General alarm event active flag',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'impactAlarmStatus': {'name': 'impactAlarmStatus',
                                      'json_key': 'impactAlarmStatus',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Impact alarm status',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'silenceAlarmStatus': {'name': 'silenceAlarmStatus',
                                       'json_key': 'silenceAlarmStatus',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'Silence alarm status',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'heightAccessAlarmStatus': {'name': 'heightAccessAlarmStatus',
                                            'json_key': 'heightAccessAlarmStatus',
                                            'data_type': 'bool',
                                            'unit': 'none',
                                            'readwrite': '0',
                                            'description': 'Height access alarm status',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '1',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'BI',
                                            'bacnet_unit': '95'},
                'heightAccessAlarmEvent': {'name': 'heightAccessAlarmEvent',
                                           'json_key': 'heightAccessAlarmEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'Height access alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'switchTimerStatus': {'name': 'switchTimerStatus',
                                      'json_key': 'switchTimerStatus',
                                      'data_type': 'int',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'min_value': '0',
                                      'max_value': '4294967295',
                                      'description': 'Switch timer status bitfield',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '2',
                                      'modbus_mapping_mode': 'big_endian',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'AI',
                                      'bacnet_unit': '95'},
                'ds103ControlTarget': {'name': 'ds103ControlTarget',
                                       'json_key': 'ds103ControlTarget',
                                       'data_type': 'int',
                                       'unit': 'none',
                                       'min_value': '1',
                                       'max_value': '255',
                                       'readwrite': '1',
                                       'description': 'DS-103 control target (1=left, 2=middle, 3=right, 254=lock, '
                                                      '255=all switches)',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AV',
                                       'bacnet_unit': '95'},
                'ds103ControlState': {'name': 'ds103ControlState',
                                      'json_key': 'ds103ControlState',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '1',
                                      'description': 'DS-103 control state (switch: 0=off,1=on; lock: 0=unlock,1=lock)',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BV',
                                      'bacnet_unit': '95'},
                'ds103ControlMode': {'name': 'ds103ControlMode',
                                     'json_key': 'ds103ControlMode',
                                     'data_type': 'int',
                                     'unit': 'none',
                                     'min_value': '0',
                                     'max_value': '4',
                                     'readwrite': '1',
                                     'description': 'DS-103 control mode (0=immediate, 1=delay, 2=schedule, '
                                                    '3=cancelTimer, 4=query)',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AV',
                                     'bacnet_unit': '95'},
                'ds103DelaySeconds': {'name': 'ds103DelaySeconds',
                                      'json_key': 'ds103DelaySeconds',
                                      'data_type': 'int',
                                      'unit': 'seconds',
                                      'min_value': '0',
                                      'max_value': '4294967295',
                                      'readwrite': '1',
                                      'description': 'DS-103 delay time in seconds for delayed commands',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '2',
                                      'modbus_mapping_mode': 'big_endian',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'AV',
                                      'bacnet_unit': '73'},
                'ds103ScheduleTimestamp': {'name': 'ds103ScheduleTimestamp',
                                           'json_key': 'ds103ScheduleTimestamp',
                                           'data_type': 'timestamp',
                                           'unit': 'seconds',
                                           'min_value': '0',
                                           'max_value': '4294967295',
                                           'readwrite': '1',
                                           'description': 'DS-103 scheduled execution timestamp in Unix seconds',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '2',
                                           'modbus_mapping_mode': 'big_endian',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'AV',
                                           'bacnet_unit': '73'},
                'ds103RepeatDaily': {'name': 'ds103RepeatDaily',
                                     'json_key': 'ds103RepeatDaily',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '1',
                                     'description': 'DS-103 schedule repeat mode (0=once, 1=daily)',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BV',
                                     'bacnet_unit': '95'},
                'ds501ControlTarget': {'name': 'ds501ControlTarget',
                                       'json_key': 'ds501ControlTarget',
                                       'data_type': 'int',
                                       'unit': 'none',
                                       'min_value': '1',
                                       'max_value': '255',
                                       'readwrite': '1',
                                       'description': 'DS-501 control target (1=socket, 254=lock, 255=query)',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AV',
                                       'bacnet_unit': '95'},
                'ds501ControlState': {'name': 'ds501ControlState',
                                      'json_key': 'ds501ControlState',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '1',
                                      'description': 'DS-501 control state (socket: 0=off,1=on; lock: 0=unlock,1=lock)',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BV',
                                      'bacnet_unit': '95'},
                'ds501ControlMode': {'name': 'ds501ControlMode',
                                     'json_key': 'ds501ControlMode',
                                     'data_type': 'int',
                                     'unit': 'none',
                                     'min_value': '0',
                                     'max_value': '4',
                                     'readwrite': '1',
                                     'description': 'DS-501 control mode (0=immediate, 1=delay, 2=schedule, '
                                                    '3=cancelTimer, 4=query)',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'AV',
                                     'bacnet_unit': '95'},
                'ds501DelaySeconds': {'name': 'ds501DelaySeconds',
                                      'json_key': 'ds501DelaySeconds',
                                      'data_type': 'int',
                                      'unit': 'seconds',
                                      'min_value': '0',
                                      'max_value': '4294967295',
                                      'readwrite': '1',
                                      'description': 'DS-501 delay time in seconds for delayed commands',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '2',
                                      'modbus_mapping_mode': 'big_endian',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'AV',
                                      'bacnet_unit': '73'},
                'ds501ScheduleTimestamp': {'name': 'ds501ScheduleTimestamp',
                                           'json_key': 'ds501ScheduleTimestamp',
                                           'data_type': 'timestamp',
                                           'unit': 'seconds',
                                           'min_value': '0',
                                           'max_value': '4294967295',
                                           'readwrite': '1',
                                           'description': 'DS-501 scheduled execution timestamp in Unix seconds',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '2',
                                           'modbus_mapping_mode': 'big_endian',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'AV',
                                           'bacnet_unit': '73'},
                'ds501RepeatDaily': {'name': 'ds501RepeatDaily',
                                     'json_key': 'ds501RepeatDaily',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '1',
                                     'description': 'DS-501 schedule repeat mode (0=once, 1=daily)',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BV',
                                     'bacnet_unit': '95'},
                'currentAvg': {'name': 'currentAvg',
                               'json_key': 'currentAvg',
                               'data_type': 'float',
                               'unit': 'ampere',
                               'decimal_places': '1',
                               'min_value': '0',
                               'max_value': '100',
                               'readwrite': '0',
                               'description': 'Average three-phase current',
                               'modbus_enable': '1',
                               'modbus_table': 'holding',
                               'modbus_register_count': '1',
                               'modbus_mapping_mode': 'single',
                               'modbus_scale': '10',
                               'bacnet_enable': '1',
                               'bacnet_object_type': 'AI',
                               'bacnet_unit': '3'},
                'activePowerB': {'name': 'activePowerB',
                                 'json_key': 'activePowerB',
                                 'data_type': 'float',
                                 'unit': 'watt',
                                 'decimal_places': '2',
                                 'min_value': '0',
                                 'max_value': '10000',
                                 'readwrite': '0',
                                 'description': 'B-phase active power',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '47'},
                'activePowerC': {'name': 'activePowerC',
                                 'json_key': 'activePowerC',
                                 'data_type': 'float',
                                 'unit': 'watt',
                                 'decimal_places': '2',
                                 'min_value': '0',
                                 'max_value': '10000',
                                 'readwrite': '0',
                                 'description': 'C-phase active power',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '47'},
                'reactivePowerA': {'name': 'reactivePowerA',
                                   'json_key': 'reactivePowerA',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '-10000',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'A-phase reactive power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '11'},
                'reactivePowerB': {'name': 'reactivePowerB',
                                   'json_key': 'reactivePowerB',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '-10000',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'B-phase reactive power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '11'},
                'reactivePowerC': {'name': 'reactivePowerC',
                                   'json_key': 'reactivePowerC',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '-10000',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'C-phase reactive power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '11'},
                'reactivePowerTotal': {'name': 'reactivePowerTotal',
                                       'json_key': 'reactivePowerTotal',
                                       'data_type': 'float',
                                       'unit': 'none',
                                       'decimal_places': '2',
                                       'min_value': '-30000',
                                       'max_value': '30000',
                                       'readwrite': '0',
                                       'description': 'Total reactive power',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '2',
                                       'modbus_mapping_mode': 'big_endian',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AI',
                                       'bacnet_unit': '11'},
                'apparentPowerA': {'name': 'apparentPowerA',
                                   'json_key': 'apparentPowerA',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'A-phase apparent power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '8'},
                'apparentPowerB': {'name': 'apparentPowerB',
                                   'json_key': 'apparentPowerB',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'B-phase apparent power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '8'},
                'apparentPowerC': {'name': 'apparentPowerC',
                                   'json_key': 'apparentPowerC',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '10000',
                                   'readwrite': '0',
                                   'description': 'C-phase apparent power',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '8'},
                'apparentPowerTotal': {'name': 'apparentPowerTotal',
                                       'json_key': 'apparentPowerTotal',
                                       'data_type': 'float',
                                       'unit': 'none',
                                       'decimal_places': '2',
                                       'min_value': '0',
                                       'max_value': '30000',
                                       'readwrite': '0',
                                       'description': 'Total apparent power',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '2',
                                       'modbus_mapping_mode': 'big_endian',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'AI',
                                       'bacnet_unit': '8'},
                'powerFactorA': {'name': 'powerFactorA',
                                 'json_key': 'powerFactorA',
                                 'data_type': 'float',
                                 'unit': 'none',
                                 'decimal_places': '3',
                                 'min_value': '0',
                                 'max_value': '1',
                                 'readwrite': '0',
                                 'description': 'A-phase power factor',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '95'},
                'powerFactorB': {'name': 'powerFactorB',
                                 'json_key': 'powerFactorB',
                                 'data_type': 'float',
                                 'unit': 'none',
                                 'decimal_places': '3',
                                 'min_value': '0',
                                 'max_value': '1',
                                 'readwrite': '0',
                                 'description': 'B-phase power factor',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '95'},
                'powerFactorC': {'name': 'powerFactorC',
                                 'json_key': 'powerFactorC',
                                 'data_type': 'float',
                                 'unit': 'none',
                                 'decimal_places': '3',
                                 'min_value': '0',
                                 'max_value': '1',
                                 'readwrite': '0',
                                 'description': 'C-phase power factor',
                                 'modbus_enable': '1',
                                 'modbus_table': 'holding',
                                 'modbus_register_count': '2',
                                 'modbus_mapping_mode': 'big_endian',
                                 'modbus_scale': '1',
                                 'bacnet_enable': '1',
                                 'bacnet_object_type': 'AI',
                                 'bacnet_unit': '95'},
                'reactiveEnergy': {'name': 'reactiveEnergy',
                                   'json_key': 'reactiveEnergy',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '999999',
                                   'readwrite': '0',
                                   'description': 'Reactive energy consumption',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '204'},
                'apparentEnergy': {'name': 'apparentEnergy',
                                   'json_key': 'apparentEnergy',
                                   'data_type': 'float',
                                   'unit': 'none',
                                   'decimal_places': '2',
                                   'min_value': '0',
                                   'max_value': '999999',
                                   'readwrite': '0',
                                   'description': 'Apparent energy consumption',
                                   'modbus_enable': '1',
                                   'modbus_table': 'holding',
                                   'modbus_register_count': '2',
                                   'modbus_mapping_mode': 'big_endian',
                                   'modbus_scale': '1',
                                   'bacnet_enable': '1',
                                   'bacnet_object_type': 'AI',
                                   'bacnet_unit': '240'},
                'tempSensor2': {'name': 'tempSensor2',
                                'json_key': 'tempSensor2',
                                'data_type': 'float',
                                'unit': 'celsius',
                                'decimal_places': '1',
                                'min_value': '-20',
                                'max_value': '110',
                                'readwrite': '0',
                                'description': 'Temperature sensor 2',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '10',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '62'},
                'tempSensor3': {'name': 'tempSensor3',
                                'json_key': 'tempSensor3',
                                'data_type': 'float',
                                'unit': 'celsius',
                                'decimal_places': '1',
                                'min_value': '-20',
                                'max_value': '110',
                                'readwrite': '0',
                                'description': 'Temperature sensor 3',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '10',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '62'},
                'tempSensor4': {'name': 'tempSensor4',
                                'json_key': 'tempSensor4',
                                'data_type': 'float',
                                'unit': 'celsius',
                                'decimal_places': '1',
                                'min_value': '-20',
                                'max_value': '110',
                                'readwrite': '0',
                                'description': 'Temperature sensor 4',
                                'modbus_enable': '1',
                                'modbus_table': 'holding',
                                'modbus_register_count': '1',
                                'modbus_mapping_mode': 'single',
                                'modbus_scale': '10',
                                'bacnet_enable': '1',
                                'bacnet_object_type': 'AI',
                                'bacnet_unit': '62'},
                'alarmOvercurrentB': {'name': 'alarmOvercurrentB',
                                      'json_key': 'alarmOvercurrentB',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'B-phase overcurrent alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmOvercurrentC': {'name': 'alarmOvercurrentC',
                                      'json_key': 'alarmOvercurrentC',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'C-phase overcurrent alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmOvervoltageA': {'name': 'alarmOvervoltageA',
                                      'json_key': 'alarmOvervoltageA',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'A-phase overvoltage alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmOvervoltageB': {'name': 'alarmOvervoltageB',
                                      'json_key': 'alarmOvervoltageB',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'B-phase overvoltage alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmOvervoltageC': {'name': 'alarmOvervoltageC',
                                      'json_key': 'alarmOvervoltageC',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'C-phase overvoltage alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmUndervoltageA': {'name': 'alarmUndervoltageA',
                                       'json_key': 'alarmUndervoltageA',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'A-phase undervoltage alarm',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'alarmUndervoltageB': {'name': 'alarmUndervoltageB',
                                       'json_key': 'alarmUndervoltageB',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'B-phase undervoltage alarm',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'alarmUndervoltageC': {'name': 'alarmUndervoltageC',
                                       'json_key': 'alarmUndervoltageC',
                                       'data_type': 'bool',
                                       'unit': 'none',
                                       'readwrite': '0',
                                       'description': 'C-phase undervoltage alarm',
                                       'modbus_enable': '1',
                                       'modbus_table': 'holding',
                                       'modbus_register_count': '1',
                                       'modbus_mapping_mode': 'single',
                                       'modbus_scale': '1',
                                       'bacnet_enable': '1',
                                       'bacnet_object_type': 'BI',
                                       'bacnet_unit': '95'},
                'alarmShortCircuit': {'name': 'alarmShortCircuit',
                                      'json_key': 'alarmShortCircuit',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Short circuit alarm',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'},
                'alarmTempSensor1': {'name': 'alarmTempSensor1',
                                     'json_key': 'alarmTempSensor1',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Temperature sensor 1 alarm',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'alarmTempSensor2': {'name': 'alarmTempSensor2',
                                     'json_key': 'alarmTempSensor2',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Temperature sensor 2 alarm',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'alarmTempSensor3': {'name': 'alarmTempSensor3',
                                     'json_key': 'alarmTempSensor3',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Temperature sensor 3 alarm',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'alarmTempSensor4': {'name': 'alarmTempSensor4',
                                     'json_key': 'alarmTempSensor4',
                                     'data_type': 'bool',
                                     'unit': 'none',
                                     'readwrite': '0',
                                     'description': 'Temperature sensor 4 alarm',
                                     'modbus_enable': '1',
                                     'modbus_table': 'holding',
                                     'modbus_register_count': '1',
                                     'modbus_mapping_mode': 'single',
                                     'modbus_scale': '1',
                                     'bacnet_enable': '1',
                                     'bacnet_object_type': 'BI',
                                     'bacnet_unit': '95'},
                'beaconRefRssi': {'name': 'beaconRefRssi',
                                  'json_key': 'beaconRefRssi',
                                  'data_type': 'int',
                                  'unit': 'none',
                                  'min_value': '-120',
                                  'max_value': '0',
                                  'readwrite': '0',
                                  'description': 'Latest beacon 1m reference RSSI',
                                  'modbus_enable': '1',
                                  'modbus_table': 'holding',
                                  'modbus_register_count': '1',
                                  'modbus_mapping_mode': 'single',
                                  'modbus_scale': '1',
                                  'bacnet_enable': '1',
                                  'bacnet_object_type': 'AI',
                                  'bacnet_unit': '95'},
                'electricalAlarmEvent': {'name': 'electricalAlarmEvent',
                                         'json_key': 'electricalAlarmEvent',
                                         'data_type': 'int',
                                         'unit': 'none',
                                         'min_value': '0',
                                         'max_value': '65535',
                                         'readwrite': '0',
                                         'description': 'Electrical fire alarm event bitfield',
                                         'modbus_enable': '1',
                                         'modbus_table': 'holding',
                                         'modbus_register_count': '1',
                                         'modbus_mapping_mode': 'single',
                                         'modbus_scale': '1',
                                         'bacnet_enable': '1',
                                         'bacnet_object_type': 'AI',
                                         'bacnet_unit': '95'},
                'alarmOvercurrentAEvent': {'name': 'alarmOvercurrentAEvent',
                                           'json_key': 'alarmOvercurrentAEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'A-phase overcurrent alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmOvercurrentBEvent': {'name': 'alarmOvercurrentBEvent',
                                           'json_key': 'alarmOvercurrentBEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'B-phase overcurrent alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmOvercurrentCEvent': {'name': 'alarmOvercurrentCEvent',
                                           'json_key': 'alarmOvercurrentCEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'C-phase overcurrent alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmOvervoltageAEvent': {'name': 'alarmOvervoltageAEvent',
                                           'json_key': 'alarmOvervoltageAEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'A-phase overvoltage alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmOvervoltageBEvent': {'name': 'alarmOvervoltageBEvent',
                                           'json_key': 'alarmOvervoltageBEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'B-phase overvoltage alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmOvervoltageCEvent': {'name': 'alarmOvervoltageCEvent',
                                           'json_key': 'alarmOvervoltageCEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'C-phase overvoltage alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmUndervoltageAEvent': {'name': 'alarmUndervoltageAEvent',
                                            'json_key': 'alarmUndervoltageAEvent',
                                            'data_type': 'bool',
                                            'unit': 'none',
                                            'readwrite': '0',
                                            'description': 'A-phase undervoltage alarm event',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '1',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'BI',
                                            'bacnet_unit': '95'},
                'alarmUndervoltageBEvent': {'name': 'alarmUndervoltageBEvent',
                                            'json_key': 'alarmUndervoltageBEvent',
                                            'data_type': 'bool',
                                            'unit': 'none',
                                            'readwrite': '0',
                                            'description': 'B-phase undervoltage alarm event',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '1',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'BI',
                                            'bacnet_unit': '95'},
                'alarmUndervoltageCEvent': {'name': 'alarmUndervoltageCEvent',
                                            'json_key': 'alarmUndervoltageCEvent',
                                            'data_type': 'bool',
                                            'unit': 'none',
                                            'readwrite': '0',
                                            'description': 'C-phase undervoltage alarm event',
                                            'modbus_enable': '1',
                                            'modbus_table': 'holding',
                                            'modbus_register_count': '1',
                                            'modbus_mapping_mode': 'single',
                                            'modbus_scale': '1',
                                            'bacnet_enable': '1',
                                            'bacnet_object_type': 'BI',
                                            'bacnet_unit': '95'},
                'alarmShortCircuitEvent': {'name': 'alarmShortCircuitEvent',
                                           'json_key': 'alarmShortCircuitEvent',
                                           'data_type': 'bool',
                                           'unit': 'none',
                                           'readwrite': '0',
                                           'description': 'Short circuit alarm event',
                                           'modbus_enable': '1',
                                           'modbus_table': 'holding',
                                           'modbus_register_count': '1',
                                           'modbus_mapping_mode': 'single',
                                           'modbus_scale': '1',
                                           'bacnet_enable': '1',
                                           'bacnet_object_type': 'BI',
                                           'bacnet_unit': '95'},
                'alarmTempSensor1Event': {'name': 'alarmTempSensor1Event',
                                          'json_key': 'alarmTempSensor1Event',
                                          'data_type': 'bool',
                                          'unit': 'none',
                                          'readwrite': '0',
                                          'description': 'Temperature sensor 1 alarm event',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '1',
                                          'modbus_mapping_mode': 'single',
                                          'modbus_scale': '1',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'BI',
                                          'bacnet_unit': '95'},
                'alarmTempSensor2Event': {'name': 'alarmTempSensor2Event',
                                          'json_key': 'alarmTempSensor2Event',
                                          'data_type': 'bool',
                                          'unit': 'none',
                                          'readwrite': '0',
                                          'description': 'Temperature sensor 2 alarm event',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '1',
                                          'modbus_mapping_mode': 'single',
                                          'modbus_scale': '1',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'BI',
                                          'bacnet_unit': '95'},
                'alarmTempSensor3Event': {'name': 'alarmTempSensor3Event',
                                          'json_key': 'alarmTempSensor3Event',
                                          'data_type': 'bool',
                                          'unit': 'none',
                                          'readwrite': '0',
                                          'description': 'Temperature sensor 3 alarm event',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '1',
                                          'modbus_mapping_mode': 'single',
                                          'modbus_scale': '1',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'BI',
                                          'bacnet_unit': '95'},
                'alarmTempSensor4Event': {'name': 'alarmTempSensor4Event',
                                          'json_key': 'alarmTempSensor4Event',
                                          'data_type': 'bool',
                                          'unit': 'none',
                                          'readwrite': '0',
                                          'description': 'Temperature sensor 4 alarm event',
                                          'modbus_enable': '1',
                                          'modbus_table': 'holding',
                                          'modbus_register_count': '1',
                                          'modbus_mapping_mode': 'single',
                                          'modbus_scale': '1',
                                          'bacnet_enable': '1',
                                          'bacnet_object_type': 'BI',
                                          'bacnet_unit': '95'},
                'alarmLeakageEvent': {'name': 'alarmLeakageEvent',
                                      'json_key': 'alarmLeakageEvent',
                                      'data_type': 'bool',
                                      'unit': 'none',
                                      'readwrite': '0',
                                      'description': 'Leakage current alarm event',
                                      'modbus_enable': '1',
                                      'modbus_table': 'holding',
                                      'modbus_register_count': '1',
                                      'modbus_mapping_mode': 'single',
                                      'modbus_scale': '1',
                                      'bacnet_enable': '1',
                                      'bacnet_object_type': 'BI',
                                      'bacnet_unit': '95'}},
 'sensor_types': {'AN_303_temperature_humidity': {'name': 'AN_303_temperature_humidity',
                                                  'attributes': ['online',
                                                                 'lastOnlineTime',
                                                                 'temperature',
                                                                 'temperatureState',
                                                                 'humidity',
                                                                 'humidityState',
                                                                 'batteryVoltage',
                                                                 'batteryVoltageState',
                                                                 'tamper',
                                                                 'mainVersion',
                                                                 'appVersion',
                                                                 'hardwareVersion',
                                                                 'model',
                                                                 'rssi',
                                                                 'snr'],
                                                  'description': 'Temperature & Humidity sensor',
                                                  'model_name': 'AN-303',
                                                  'version': '20260101',
                                                  'modbus_block_span': '48',
                                                  'bacnet_block_span': '20'},
                  'AN_304_infrared_detector': {'name': 'AN_304_infrared_detector',
                                               'attributes': ['online',
                                                              'lastOnlineTime',
                                                              'batteryVoltage',
                                                              'batteryVoltageState',
                                                              'tamper',
                                                              'tamperEvent',
                                                              'infraredEvent',
                                                              'mainVersion',
                                                              'appVersion',
                                                              'hardwareVersion',
                                                              'model',
                                                              'rssi',
                                                              'snr'],
                                               'description': 'Infrared Detector',
                                               'model_name': 'AN-304',
                                               'version': '20260101',
                                               'modbus_block_span': '48',
                                               'bacnet_block_span': '20'},
                  'JTY_AN_503A_smoke_detector': {'name': 'JTY_AN_503A_smoke_detector',
                                                 'attributes': ['online',
                                                                'lastOnlineTime',
                                                                'temperature',
                                                                'batteryVoltage',
                                                                'batteryVoltageState',
                                                                'tamper',
                                                                'tamperEvent',
                                                                'smokeEvent',
                                                                'smokeStatus',
                                                                'selfCheckEvent',
                                                                'mainVersion',
                                                                'appVersion',
                                                                'hardwareVersion',
                                                                'model',
                                                                'rssi',
                                                                'snr'],
                                                 'description': 'Smoke Detector',
                                                 'model_name': 'JTY-AN-503A',
                                                 'version': '20260101',
                                                 'modbus_block_span': '58',
                                                 'bacnet_block_span': '30'},
                  'CU606_air_quality_sensor': {'name': 'CU606_air_quality_sensor',
                                               'attributes': ['online',
                                                              'lastOnlineTime',
                                                              'temperature',
                                                              'humidity',
                                                              'batteryVoltage',
                                                              'batteryVoltageState',
                                                              'co2',
                                                              'pm25',
                                                              'formaldehyde',
                                                              'tvoc',
                                                              'mainVersion',
                                                              'appVersion',
                                                              'hardwareVersion',
                                                              'model',
                                                              'rssi',
                                                              'snr'],
                                               'description': 'Air Quality Sensor',
                                               'model_name': 'CU606',
                                               'version': '20260101',
                                               'modbus_block_span': '58',
                                               'bacnet_block_span': '20'},
                  'W8004_thermostat': {'name': 'W8004_thermostat',
                                       'attributes': ['online',
                                                      'lastOnlineTime',
                                                      'powerState',
                                                      'setTemperature',
                                                      'workMode',
                                                      'fanSpeed',
                                                      'temperature',
                                                      'humidity',
                                                      'keyLockState',
                                                      'valveState',
                                                      'signalStrength',
                                                      'cumulativeOnTime',
                                                      'cumulativeValveOpenTime',
                                                      'mainVersion',
                                                      'appVersion',
                                                      'hardwareVersion',
                                                      'model',
                                                      'rssi',
                                                      'snr'],
                                       'description': 'Thermostat Controller',
                                       'model_name': 'W8004',
                                       'version': '20260101',
                                       'modbus_block_span': '58',
                                       'bacnet_block_span': '20'},
                  'DS_501_socket': {'name': 'DS_501_socket',
                                    'attributes': ['online',
                                                   'lastOnlineTime',
                                                   'ds501ControlTarget',
                                                   'ds501ControlState',
                                                   'ds501ControlMode',
                                                   'ds501DelaySeconds',
                                                   'ds501ScheduleTimestamp',
                                                   'ds501RepeatDaily',
                                                   'switch',
                                                   'lockState',
                                                   'voltage',
                                                   'current',
                                                   'activePower',
                                                   'energy',
                                                   'timestamp',
                                                   'timerCloseEnabled',
                                                   'timerOpenEnabled',
                                                   'timerLockEnabled',
                                                   'timerUnlockEnabled',
                                                   'mainVersion',
                                                   'appVersion',
                                                   'hardwareVersion',
                                                   'model',
                                                   'rssi',
                                                   'snr'],
                                    'description': 'Smart Socket Panel',
                                    'model_name': 'DS-501',
                                    'version': '20260101',
                                    'modbus_block_span': '68',
                                    'bacnet_block_span': '30'},
                  'EF5600_DN1_electrical_fire_monitor': {'name': 'EF5600_DN1_electrical_fire_monitor',
                                                         'attributes': ['online',
                                                                        'lastOnlineTime',
                                                                        'ef5600CommandCode',
                                                                        'ef5600SettingAddress',
                                                                        'ef5600SettingValueHigh',
                                                                        'ef5600SettingValueLow',
                                                                        'switch',
                                                                        'voltageA',
                                                                        'voltageB',
                                                                        'voltageC',
                                                                        'voltageAvg',
                                                                        'currentA',
                                                                        'currentB',
                                                                        'currentC',
                                                                        'currentAvg',
                                                                        'activePowerA',
                                                                        'activePowerB',
                                                                        'activePowerC',
                                                                        'activePowerTotal',
                                                                        'reactivePowerA',
                                                                        'reactivePowerB',
                                                                        'reactivePowerC',
                                                                        'reactivePowerTotal',
                                                                        'apparentPowerA',
                                                                        'apparentPowerB',
                                                                        'apparentPowerC',
                                                                        'apparentPowerTotal',
                                                                        'powerFactorA',
                                                                        'powerFactorB',
                                                                        'powerFactorC',
                                                                        'powerFactorTotal',
                                                                        'activeEnergy',
                                                                        'reactiveEnergy',
                                                                        'apparentEnergy',
                                                                        'leakageCurrent',
                                                                        'tempSensor1',
                                                                        'tempSensor2',
                                                                        'tempSensor3',
                                                                        'tempSensor4',
                                                                        'tempAvg',
                                                                        'envTemperature',
                                                                        'envHumidity',
                                                                        'electricalAlarm',
                                                                        'electricalAlarmEvent',
                                                                        'alarmOvercurrentA',
                                                                        'alarmOvercurrentB',
                                                                        'alarmOvercurrentC',
                                                                        'alarmOvercurrentAEvent',
                                                                        'alarmOvercurrentBEvent',
                                                                        'alarmOvercurrentCEvent',
                                                                        'alarmOvervoltageA',
                                                                        'alarmOvervoltageB',
                                                                        'alarmOvervoltageC',
                                                                        'alarmOvervoltageAEvent',
                                                                        'alarmOvervoltageBEvent',
                                                                        'alarmOvervoltageCEvent',
                                                                        'alarmUndervoltageA',
                                                                        'alarmUndervoltageB',
                                                                        'alarmUndervoltageC',
                                                                        'alarmUndervoltageAEvent',
                                                                        'alarmUndervoltageBEvent',
                                                                        'alarmUndervoltageCEvent',
                                                                        'alarmShortCircuit',
                                                                        'alarmShortCircuitEvent',
                                                                        'alarmTempSensor1',
                                                                        'alarmTempSensor2',
                                                                        'alarmTempSensor3',
                                                                        'alarmTempSensor4',
                                                                        'alarmTempSensor1Event',
                                                                        'alarmTempSensor2Event',
                                                                        'alarmTempSensor3Event',
                                                                        'alarmTempSensor4Event',
                                                                        'alarmLeakage',
                                                                        'alarmLeakageEvent',
                                                                        'mainVersion',
                                                                        'appVersion',
                                                                        'hardwareVersion',
                                                                        'model',
                                                                        'rssi',
                                                                        'snr'],
                                                         'description': 'Electrical Fire Monitor',
                                                         'model_name': 'EF5600-DN1',
                                                         'version': '20260101',
                                                         'modbus_block_span': '138',
                                                         'bacnet_block_span': '80'},
                  'AN_301_emergency_button': {'name': 'AN_301_emergency_button',
                                              'attributes': ['online',
                                                             'lastOnlineTime',
                                                             'batteryVoltage',
                                                             'tamperStatus',
                                                             'tamperEvent',
                                                             'sosEvent',
                                                             'sosEventTime',
                                                             'mainVersion',
                                                             'appVersion',
                                                             'hardwareVersion',
                                                             'model',
                                                             'rssi',
                                                             'snr'],
                                              'description': 'Emergency Button/SOS Device',
                                              'model_name': 'AN-301',
                                              'version': '20260101',
                                              'modbus_block_span': '48',
                                              'bacnet_block_span': '20'},
                  'undefine': {'name': 'undefine',
                               'attributes': ['online',
                                              'lastOnlineTime',
                                              'lastFport',
                                              'lastPayloadLen',
                                              'lastPayload',
                                              'rssi',
                                              'snr'],
                               'description': 'undefine sensor',
                               'version': '20260101',
                               'modbus_block_span': '145',
                               'bacnet_block_span': '20'},
                  'AN_305_door_contact': {'name': 'AN_305_door_contact',
                                          'attributes': ['online',
                                                         'lastOnlineTime',
                                                         'doorState',
                                                         'batteryVoltage',
                                                         'batteryVoltageState',
                                                         'tamperStatus',
                                                         'batteryLevel',
                                                         'tamperEvent',
                                                         'doorEvent',
                                                         'mainVersion',
                                                         'appVersion',
                                                         'hardwareVersion',
                                                         'model',
                                                         'rssi',
                                                         'snr'],
                                          'description': 'Door Contact Sensor',
                                          'model_name': 'AN-305',
                                          'version': '20260101',
                                          'modbus_block_span': '48',
                                          'bacnet_block_span': '20'},
                  'AN_204_water_leakage': {'name': 'AN_204_water_leakage',
                                           'attributes': ['online',
                                                          'lastOnlineTime',
                                                          'batteryVoltage',
                                                          'waterStatus',
                                                          'waterDuration',
                                                          'batteryLowEvent',
                                                          'waterEvent',
                                                          'mainVersion',
                                                          'appVersion',
                                                          'hardwareVersion',
                                                          'model',
                                                          'rssi',
                                                          'snr'],
                                           'description': 'Water Leakage Sensor',
                                           'model_name': 'AN-204',
                                           'version': '20260101',
                                           'modbus_block_span': '48',
                                           'bacnet_block_span': '20'},
                  'AN_201G_vibrating_wire_strain_gauge': {'name': 'AN_201G_vibrating_wire_strain_gauge',
                                                          'attributes': ['online',
                                                                         'lastOnlineTime',
                                                                         'batteryVoltage',
                                                                         'batteryVoltageState',
                                                                         'timestamp',
                                                                         'vibratingWireSensorModel',
                                                                         'frequency',
                                                                         'frequencyDigit',
                                                                         'temperature',
                                                                         'correctionFactor',
                                                                         'initialFrequency',
                                                                         'initialFrequencyDigit',
                                                                         'initialTemperature',
                                                                         'steelStructureStrain',
                                                                         'concreteStructureStrain',
                                                                         'batteryLowAlarm',
                                                                         'isHeartbeat',
                                                                         'mainVersion',
                                                                         'appVersion',
                                                                         'hardwareVersion',
                                                                         'model',
                                                                         'rssi',
                                                                         'snr'],
                                                          'description': 'Vibrating Wire Strain Gauge',
                                                          'model_name': 'AN-201G',
                                                          'version': '20260101',
                                                          'modbus_block_span': '88',
                                                          'bacnet_block_span': '30'},
                  'AN_113_tilt_angle': {'name': 'AN_113_tilt_angle',
                                        'attributes': ['online',
                                                       'lastOnlineTime',
                                                       'batteryVoltage',
                                                       'batteryVoltageState',
                                                       'tamper',
                                                       'tiltAngle',
                                                       'accelerationAlarm',
                                                       'tiltAlarm',
                                                       'batteryLowEvent',
                                                       'tamperEvent',
                                                       'mainVersion',
                                                       'appVersion',
                                                       'hardwareVersion',
                                                       'model',
                                                       'rssi',
                                                       'snr'],
                                        'description': 'Tilt/Angle Sensor',
                                        'model_name': 'AN-113',
                                        'version': '20260101',
                                        'modbus_block_span': '58',
                                        'bacnet_block_span': '20'},
                  'AN_122_beacon_tracker': {'name': 'AN_122_beacon_tracker',
                                            'attributes': ['online',
                                                           'lastOnlineTime',
                                                           'batteryLevel',
                                                           'tamper',
                                                           'latitude',
                                                           'longitude',
                                                           'positionAccuracy',
                                                           'beaconIdHex',
                                                           'beaconRefRssi',
                                                           'beaconRssi',
                                                           'beaconBatteryLevel',
                                                           'beaconBatteryValid',
                                                           'tiltAngle',
                                                           'batteryLowAlarm',
                                                           'tamperEvent',
                                                           'accelerationAlarm',
                                                           'tiltAlarm',
                                                           'mainVersion',
                                                           'appVersion',
                                                           'hardwareVersion',
                                                           'model',
                                                           'rssi',
                                                           'snr'],
                                            'description': 'Beacon Tracker with GPS',
                                            'model_name': 'AN-122',
                                            'version': '20260101',
                                            'modbus_block_span': '78',
                                            'bacnet_block_span': '30'},
                  'AN_306_radar_presence': {'name': 'AN_306_radar_presence',
                                            'attributes': ['online',
                                                           'lastOnlineTime',
                                                           'presence',
                                                           'tamper',
                                                           'presenceEvent',
                                                           'tamperEvent',
                                                           'isHeartbeat',
                                                           'mainVersion',
                                                           'appVersion',
                                                           'hardwareVersion',
                                                           'model',
                                                           'rssi',
                                                           'snr'],
                                            'description': 'Radar Human Presence Sensor',
                                            'model_name': 'AN-306',
                                            'version': '20260101',
                                            'modbus_block_span': '48',
                                            'bacnet_block_span': '20'},
                  'AN_308_light_illuminance': {'name': 'AN_308_light_illuminance',
                                               'attributes': ['online',
                                                              'lastOnlineTime',
                                                              'batteryVoltage',
                                                              'batteryVoltageState',
                                                              'tamper',
                                                              'illuminance',
                                                              'batteryLowEvent',
                                                              'tamperEvent',
                                                              'mainVersion',
                                                              'appVersion',
                                                              'hardwareVersion',
                                                              'model',
                                                              'rssi',
                                                              'snr'],
                                               'description': 'Light Illuminance Sensor',
                                               'model_name': 'AN-308',
                                               'version': '20260101',
                                               'modbus_block_span': '48',
                                               'bacnet_block_span': '20'},
                  'EX205_liquid_level': {'name': 'EX205_liquid_level',
                                         'attributes': ['online',
                                                        'lastOnlineTime',
                                                        'batteryVoltage',
                                                        'batteryVoltageState',
                                                        'distance',
                                                        'liquidLevel',
                                                        'liquidLevelPercent',
                                                        'liquidLevelStatus',
                                                        'liquidLevelEvent',
                                                        'batteryLowEvent',
                                                        'sensorAbnormal',
                                                        'mainVersion',
                                                        'appVersion',
                                                        'hardwareVersion',
                                                        'model',
                                                        'rssi',
                                                        'snr'],
                                         'description': 'Radar Liquid Level Meter',
                                         'model_name': 'EX205',
                                         'version': '20260101',
                                         'modbus_block_span': '58',
                                         'bacnet_block_span': '20'},
                  'AN_307_sound_light_alarm': {'name': 'AN_307_sound_light_alarm',
                                               'attributes': ['online',
                                                              'lastOnlineTime',
                                                              'alarmStatus',
                                                              'alarmDurationSeconds',
                                                              'mainVersion',
                                                              'appVersion',
                                                              'hardwareVersion',
                                                              'model',
                                                              'rssi',
                                                              'snr'],
                                               'description': 'Sound & Light Alarm',
                                               'model_name': 'AN-307',
                                               'version': '20260101',
                                               'modbus_block_span': '48',
                                               'bacnet_block_span': '20'},
                  'DS_103_3ch_switch': {'name': 'DS_103_3ch_switch',
                                        'attributes': ['online',
                                                       'lastOnlineTime',
                                                       'ds103ControlTarget',
                                                       'ds103ControlState',
                                                       'ds103ControlMode',
                                                       'ds103DelaySeconds',
                                                       'ds103ScheduleTimestamp',
                                                       'ds103RepeatDaily',
                                                       'lockState',
                                                       'switch1State',
                                                       'switch2State',
                                                       'switch3State',
                                                       'timestamp',
                                                       'switchTimerStatus',
                                                       'timerCloseEnabled1',
                                                       'timerOpenEnabled1',
                                                       'timerCloseEnabled2',
                                                       'timerOpenEnabled2',
                                                       'timerCloseEnabled3',
                                                       'timerOpenEnabled3',
                                                       'timerLockEnabled',
                                                       'timerUnlockEnabled',
                                                       'mainVersion',
                                                       'appVersion',
                                                       'hardwareVersion',
                                                       'model',
                                                       'rssi',
                                                       'snr'],
                                        'description': '3-Channel Switch Controller',
                                        'model_name': 'DS-103',
                                        'version': '20260101',
                                        'modbus_block_span': '68',
                                        'bacnet_block_span': '30'},
                  'EX301_vibration': {'name': 'EX301_vibration',
                                      'attributes': ['online',
                                                     'lastOnlineTime',
                                                     'batteryVoltage',
                                                     'batteryVoltageState',
                                                     'temperature',
                                                     'temperatureAlarmStatus',
                                                     'vibFreqX',
                                                     'vibFreqY',
                                                     'vibFreqZ',
                                                     'vibAccelX',
                                                     'vibAccelY',
                                                     'vibAccelZ',
                                                     'vibVelX',
                                                     'vibVelY',
                                                     'vibVelZ',
                                                     'vibDispX',
                                                     'vibDispY',
                                                     'vibDispZ',
                                                     'vibrationAlarmStatus',
                                                     'alarmAccelX',
                                                     'alarmAccelY',
                                                     'alarmAccelZ',
                                                     'alarmVelX',
                                                     'alarmVelY',
                                                     'alarmVelZ',
                                                     'alarmDispX',
                                                     'alarmDispY',
                                                     'alarmDispZ',
                                                     'sensorAbnormal',
                                                     'batteryLowEvent',
                                                     'vibrationAlarmEvent',
                                                     'alarmEventActive',
                                                     'mainVersion',
                                                     'appVersion',
                                                     'hardwareVersion',
                                                     'model',
                                                     'rssi',
                                                     'snr'],
                                      'description': 'Vibration Sensor',
                                      'model_name': 'EX301',
                                      'version': '20260101',
                                      'modbus_block_span': '78',
                                      'bacnet_block_span': '50'},
                  'CM100_beacon_receiver': {'name': 'CM100_beacon_receiver',
                                            'attributes': ['online',
                                                           'lastOnlineTime',
                                                           'batteryLevel',
                                                           'beaconIdHex',
                                                           'beaconRssi',
                                                           'beaconBatteryLevel',
                                                           'beaconBatteryValid',
                                                           'batteryLowAlarm',
                                                           'sosEvent',
                                                           'isHeartbeat',
                                                           'mainVersion',
                                                           'appVersion',
                                                           'hardwareVersion',
                                                           'model',
                                                           'rssi',
                                                           'snr'],
                                            'description': 'Beacon Receiver/Gateway',
                                            'model_name': 'CM100',
                                            'version': '20260101',
                                            'modbus_block_span': '68',
                                            'bacnet_block_span': '20'},
                  'GB100_safety_helmet': {'name': 'GB100_safety_helmet',
                                          'attributes': ['online',
                                                         'lastOnlineTime',
                                                         'batteryLevel',
                                                         'atmosphericPressure',
                                                         'altitude',
                                                         'temperature',
                                                         'temperatureAlarmStatus',
                                                         'fallAlarmStatus',
                                                         'fallAlarmEvent',
                                                         'helmetRemovalAlarmStatus',
                                                         'helmetRemovalAlarmEvent',
                                                         'electricityProximityAlarmStatus',
                                                         'electricityProximityAlarmEvent',
                                                         'impactAlarmStatus',
                                                         'impactAlarmEvent',
                                                         'silenceAlarmStatus',
                                                         'silenceAlarmEvent',
                                                         'heightAccessAlarmStatus',
                                                         'heightAccessAlarmEvent',
                                                         'latitude',
                                                         'longitude',
                                                         'positionAccuracy',
                                                         'gpsAbsoluteTimestamp',
                                                         'gpsTimeValid',
                                                         'beaconIdHex',
                                                         'beaconRssi',
                                                         'beaconBatteryLevel',
                                                         'beaconBatteryValid',
                                                         'batteryLowAlarm',
                                                         'temperatureEvent',
                                                         'sosEvent',
                                                         'safetyAlarmActive',
                                                         'isHeartbeat',
                                                         'mainVersion',
                                                         'appVersion',
                                                         'hardwareVersion',
                                                         'model',
                                                         'rssi',
                                                         'snr'],
                                          'description': 'Safety Helmet with Multiple Sensors',
                                          'model_name': 'GB100',
                                          'version': '20260101',
                                          'modbus_block_span': '98',
                                          'bacnet_block_span': '40'}}}



def _parse_uci_value(value):
    value = value.strip()
    if not value:
        return value

    if value[0] == "'":
        end_index = value.find("'", 1)
        if end_index != -1:
            return value[1:end_index]

    comment_index = value.find("#")
    if comment_index != -1:
        value = value[:comment_index].rstrip()

    return value


def resolve_config_snapshot_path():
    script_dir = Path(__file__).resolve().parent
    candidates = []

    for parent in (script_dir, *script_dir.parents):
        candidates.append(parent / CONFIG_SNAPSHOT_NAME)

    seen = set()
    for candidate in candidates:
        normalized = str(candidate)
        if normalized in seen:
            continue
        seen.add(normalized)
        if candidate.exists():
            return candidate

    return None


def load_live_uci_config(file_path):
    lines = Path(file_path).read_text(encoding="utf-8").splitlines()
    globals_cfg = {}
    sensor_types = {}
    attributes = {}
    section_type = None
    section_name = None

    for raw_line in lines:
        line = raw_line.strip()
        if not line or line.startswith("#"):
            continue

        config_match = re.match(r"^config\s+(\S+)\s+'(.*)'$", line)
        if config_match:
            section_type, section_name = config_match.group(1), config_match.group(2)
            if section_type == "global":
                globals_cfg = {}
            elif section_type == "sensor_type":
                sensor_types[section_name] = {"attributes": []}
            elif section_type == "attribute":
                attributes[section_name] = {}
            continue

        option_match = re.match(r"^option\s+(\S+)\s+(.+)$", line)
        if option_match and section_type:
            key = option_match.group(1)
            value = _parse_uci_value(option_match.group(2))
            if section_type == "global":
                globals_cfg[key] = value
            elif section_type == "sensor_type":
                sensor_types[section_name][key] = value
            elif section_type == "attribute":
                attributes[section_name][key] = value
            continue

        list_match = re.match(r"^list\s+(\S+)\s+(.+)$", line)
        if list_match and section_type == "sensor_type":
            key = list_match.group(1)
            value = _parse_uci_value(list_match.group(2))
            sensor_types[section_name].setdefault(key, []).append(value)

    return {
        "globals": globals_cfg,
        "sensor_types": sensor_types,
        "attributes": attributes,
    }




def _apply_latest_track_projection_overrides(config_data):
    sensor_types = config_data.setdefault("sensor_types", {})
    attributes = config_data.setdefault("attributes", {})

    latest_beacon_attributes = {
        "beaconIdHex": {
            "json_key": "beaconIdHex",
            "data_type": "string",
            "unit": "none",
            "readwrite": "0",
            "description": "Latest beacon identifier in hexadecimal",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "16",
            "modbus_mapping_mode": "string",
            "bacnet_enable": "1",
            "bacnet_object_type": "CV",
            "bacnet_unit": "95",
        },
        "beaconRefRssi": {
            "json_key": "beaconRefRssi",
            "data_type": "int",
            "unit": "none",
            "min_value": "-120",
            "max_value": "0",
            "readwrite": "0",
            "description": "Latest beacon 1m reference RSSI",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "1",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "beaconRssi": {
            "json_key": "beaconRssi",
            "data_type": "int",
            "unit": "none",
            "min_value": "-120",
            "max_value": "0",
            "readwrite": "0",
            "description": "Latest beacon RSSI signal strength",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "1",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "beaconBatteryLevel": {
            "json_key": "beaconBatteryLevel",
            "data_type": "int",
            "unit": "percent",
            "min_value": "0",
            "max_value": "100",
            "readwrite": "0",
            "description": "Latest beacon battery level percentage",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "1",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "98",
        },
        "beaconBatteryValid": {
            "json_key": "beaconBatteryValid",
            "data_type": "bool",
            "unit": "none",
            "readwrite": "0",
            "description": "Latest beacon battery level valid flag",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "1",
            "bacnet_enable": "1",
            "bacnet_object_type": "BI",
            "bacnet_unit": "95",
        },
    }
    attributes.update(latest_beacon_attributes)

    an201g_attributes = {
        "vibratingWireSensorModel": {
            "json_key": "vibratingWireSensorModel",
            "data_type": "int",
            "unit": "none",
            "min_value": "0",
            "max_value": "255",
            "readwrite": "0",
            "description": "Vibrating wire sensor model code",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "1",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "frequency": {
            "json_key": "frequency",
            "data_type": "float",
            "unit": "Hz",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Latest vibrating wire frequency",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "frequencyDigit": {
            "json_key": "frequencyDigit",
            "data_type": "float",
            "unit": "digit",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Latest frequency modulus digit calculated by f^2/1000",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "initialFrequency": {
            "json_key": "initialFrequency",
            "data_type": "float",
            "unit": "Hz",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Initial baseline vibrating wire frequency",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "initialFrequencyDigit": {
            "json_key": "initialFrequencyDigit",
            "data_type": "float",
            "unit": "digit",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Initial baseline frequency modulus digit calculated by f^2/1000",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "initialTemperature": {
            "json_key": "initialTemperature",
            "data_type": "float",
            "unit": "degrees_celsius",
            "decimal_places": "1",
            "readwrite": "0",
            "description": "Initial baseline temperature",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "1",
            "modbus_mapping_mode": "single",
            "modbus_scale": "10",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "62",
        },
        "correctionFactor": {
            "json_key": "correctionFactor",
            "data_type": "float",
            "unit": "none",
            "decimal_places": "4",
            "readwrite": "0",
            "description": "Average correction factor C used in strain calculation, default 1.0",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "10000",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "steelStructureStrain": {
            "json_key": "steelStructureStrain",
            "data_type": "float",
            "unit": "microstrain",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Derived strain for surface-mounted steel structure",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
        "concreteStructureStrain": {
            "json_key": "concreteStructureStrain",
            "data_type": "float",
            "unit": "microstrain",
            "decimal_places": "2",
            "readwrite": "0",
            "description": "Derived strain for surface-mounted concrete structure",
            "modbus_enable": "1",
            "modbus_table": "holding",
            "modbus_register_count": "2",
            "modbus_mapping_mode": "big_endian",
            "modbus_scale": "100",
            "bacnet_enable": "1",
            "bacnet_object_type": "AI",
            "bacnet_unit": "95",
        },
    }
    attributes.update(an201g_attributes)

    sensor_types.setdefault(
        AN201G_SENSOR_TYPE,
        {
            "name": AN201G_SENSOR_TYPE,
            "model_name": "AN-201G",
            "modbus_block_span": "88",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "timestamp", "vibratingWireSensorModel", "frequency", "frequencyDigit",
                "temperature", "correctionFactor", "initialFrequency", "initialFrequencyDigit", "initialTemperature", "steelStructureStrain",
                "concreteStructureStrain", "batteryLowAlarm", "isHeartbeat", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
    )

    sensor_overrides = {
        AN201G_SENSOR_TYPE: {
            "model_name": "AN-201G",
            "modbus_block_span": "88",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "timestamp", "vibratingWireSensorModel", "frequency", "frequencyDigit",
                "temperature", "correctionFactor", "initialFrequency", "initialFrequencyDigit", "initialTemperature", "steelStructureStrain",
                "concreteStructureStrain", "batteryLowAlarm", "isHeartbeat", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_113_tilt_angle": {
            "modbus_block_span": "58",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "tamper", "tiltAngle", "accelerationAlarm", "tiltAlarm",
                "batteryLowEvent", "tamperEvent", "mainVersion", "appVersion",
                "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_122_beacon_tracker": {
            "modbus_block_span": "78",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "batteryLevel", "tamper", "latitude",
                "longitude", "positionAccuracy", "beaconIdHex", "beaconRefRssi",
                "beaconRssi", "beaconBatteryLevel", "beaconBatteryValid", "tiltAngle",
                "batteryLowAlarm", "tamperEvent", "accelerationAlarm", "tiltAlarm",
                "mainVersion", "appVersion", "hardwareVersion",
                "model", "rssi", "snr",
            ],
        },
        "AN_204_water_leakage": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "waterStatus",
                "waterDuration", "batteryLowEvent", "waterEvent", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_301_emergency_button": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "tamperStatus",
                "tamperEvent", "sosEvent", "sosEventTime", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_303_temperature_humidity": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "temperature", "temperatureState",
                "humidity", "humidityState", "batteryVoltage", "batteryVoltageState",
                "tamper", "mainVersion", "appVersion", "hardwareVersion",
                "model", "rssi", "snr",
            ],
        },
        "AN_304_infrared_detector": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "tamper", "tamperEvent", "infraredEvent", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_305_door_contact": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "doorState", "batteryVoltage",
                "batteryVoltageState", "tamperStatus", "batteryLevel", "tamperEvent",
                "doorEvent", "mainVersion", "appVersion", "hardwareVersion",
                "model", "rssi", "snr",
            ],
        },
        "AN_306_radar_presence": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "presence", "tamper", "presenceEvent",
                "tamperEvent", "isHeartbeat", "mainVersion", "appVersion",
                "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_307_sound_light_alarm": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "alarmStatus", "alarmDurationSeconds",
                "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "AN_308_light_illuminance": {
            "modbus_block_span": "48",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "tamper", "illuminance", "batteryLowEvent", "tamperEvent",
                "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "CM100_beacon_receiver": {
            "modbus_block_span": "68",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryLevel", "beaconIdHex", "beaconRssi",
                "beaconBatteryLevel", "beaconBatteryValid", "batteryLowAlarm", "sosEvent",
                "isHeartbeat", "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "CU606_air_quality_sensor": {
            "modbus_block_span": "58",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "temperature", "humidity", "batteryVoltage",
                "batteryVoltageState", "co2", "pm25", "formaldehyde", "tvoc",
                "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "DS_103_3ch_switch": {
            "modbus_block_span": "68",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "ds103ControlTarget", "ds103ControlState",
                "ds103ControlMode", "ds103DelaySeconds", "ds103ScheduleTimestamp",
                "ds103RepeatDaily", "lockState", "switch1State", "switch2State",
                "switch3State", "timestamp", "switchTimerStatus", "timerCloseEnabled1",
                "timerOpenEnabled1", "timerCloseEnabled2", "timerOpenEnabled2",
                "timerCloseEnabled3", "timerOpenEnabled3", "timerLockEnabled",
                "timerUnlockEnabled", "mainVersion", "appVersion", "hardwareVersion",
                "model", "rssi", "snr",
            ],
        },
        "DS_501_socket": {
            "modbus_block_span": "68",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "ds501ControlTarget", "ds501ControlState",
                "ds501ControlMode", "ds501DelaySeconds", "ds501ScheduleTimestamp",
                "ds501RepeatDaily", "switch", "lockState", "voltage", "current",
                "activePower", "energy", "timestamp", "timerCloseEnabled",
                "timerOpenEnabled", "timerLockEnabled", "timerUnlockEnabled",
                "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "EF5600_DN1_electrical_fire_monitor": {
            "modbus_block_span": "138",
            "bacnet_block_span": "80",
            "attributes": [
                "online", "lastOnlineTime", "ef5600CommandCode", "ef5600SettingAddress",
                "ef5600SettingValueHigh", "ef5600SettingValueLow", "switch", "voltageA",
                "voltageB", "voltageC", "voltageAvg", "currentA", "currentB", "currentC",
                "currentAvg", "activePowerA", "activePowerB", "activePowerC",
                "activePowerTotal", "reactivePowerA", "reactivePowerB", "reactivePowerC",
                "reactivePowerTotal", "apparentPowerA", "apparentPowerB", "apparentPowerC",
                "apparentPowerTotal", "powerFactorA", "powerFactorB", "powerFactorC",
                "powerFactorTotal", "activeEnergy", "reactiveEnergy", "apparentEnergy",
                "leakageCurrent", "tempSensor1", "tempSensor2", "tempSensor3", "tempSensor4",
                "tempAvg", "envTemperature", "envHumidity", "electricalAlarm",
                "electricalAlarmEvent", "alarmOvercurrentA", "alarmOvercurrentB",
                "alarmOvercurrentC", "alarmOvercurrentAEvent", "alarmOvercurrentBEvent",
                "alarmOvercurrentCEvent", "alarmOvervoltageA", "alarmOvervoltageB",
                "alarmOvervoltageC", "alarmOvervoltageAEvent", "alarmOvervoltageBEvent",
                "alarmOvervoltageCEvent", "alarmUndervoltageA", "alarmUndervoltageB",
                "alarmUndervoltageC", "alarmUndervoltageAEvent", "alarmUndervoltageBEvent",
                "alarmUndervoltageCEvent", "alarmShortCircuit", "alarmShortCircuitEvent",
                "alarmTempSensor1", "alarmTempSensor2", "alarmTempSensor3", "alarmTempSensor4",
                "alarmTempSensor1Event", "alarmTempSensor2Event", "alarmTempSensor3Event",
                "alarmTempSensor4Event", "alarmLeakage", "alarmLeakageEvent", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "EX205_liquid_level": {
            "modbus_block_span": "58",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "distance", "liquidLevel", "liquidLevelPercent", "liquidLevelStatus",
                "liquidLevelEvent", "batteryLowEvent", "sensorAbnormal", "mainVersion",
                "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "EX301_vibration": {
            "modbus_block_span": "78",
            "bacnet_block_span": "50",
            "attributes": [
                "online", "lastOnlineTime", "batteryVoltage", "batteryVoltageState",
                "temperature", "temperatureAlarmStatus", "vibFreqX", "vibFreqY", "vibFreqZ",
                "vibAccelX", "vibAccelY", "vibAccelZ", "vibVelX", "vibVelY", "vibVelZ",
                "vibDispX", "vibDispY", "vibDispZ", "vibrationAlarmStatus", "alarmAccelX",
                "alarmAccelY", "alarmAccelZ", "alarmVelX", "alarmVelY", "alarmVelZ",
                "alarmDispX", "alarmDispY", "alarmDispZ", "sensorAbnormal", "batteryLowEvent",
                "vibrationAlarmEvent", "alarmEventActive", "mainVersion", "appVersion",
                "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "GB100_safety_helmet": {
            "modbus_block_span": "98",
            "bacnet_block_span": "40",
            "attributes": [
                "online", "lastOnlineTime", "batteryLevel", "atmosphericPressure", "altitude",
                "temperature", "temperatureAlarmStatus", "fallAlarmStatus", "fallAlarmEvent",
                "helmetRemovalAlarmStatus", "helmetRemovalAlarmEvent",
                "electricityProximityAlarmStatus", "electricityProximityAlarmEvent",
                "impactAlarmStatus", "impactAlarmEvent", "silenceAlarmStatus",
                "silenceAlarmEvent", "heightAccessAlarmStatus", "heightAccessAlarmEvent",
                "latitude", "longitude", "positionAccuracy",
                "gpsAbsoluteTimestamp", "gpsTimeValid", "beaconIdHex", "beaconRssi",
                "beaconBatteryLevel", "beaconBatteryValid", "batteryLowAlarm",
                "temperatureEvent", "sosEvent", "safetyAlarmActive", "isHeartbeat",
                "mainVersion", "appVersion", "hardwareVersion",
                "model", "rssi", "snr",
            ],
        },
        "JTY_AN_503A_smoke_detector": {
            "modbus_block_span": "58",
            "bacnet_block_span": "30",
            "attributes": [
                "online", "lastOnlineTime", "temperature", "batteryVoltage",
                "batteryVoltageState", "tamper", "tamperEvent", "smokeEvent",
                "smokeStatus", "selfCheckEvent", "mainVersion", "appVersion",
                "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "W8004_thermostat": {
            "modbus_block_span": "58",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "powerState", "setTemperature", "workMode",
                "fanSpeed", "temperature", "humidity", "keyLockState", "valveState",
                "signalStrength", "cumulativeOnTime", "cumulativeValveOpenTime",
                "mainVersion", "appVersion", "hardwareVersion", "model", "rssi", "snr",
            ],
        },
        "undefine": {
            "modbus_block_span": "145",
            "bacnet_block_span": "20",
            "attributes": [
                "online", "lastOnlineTime", "lastFport", "lastPayloadLen",
                "lastPayload", "rssi", "snr",
            ],
        },
    }
    for sensor_name, override in sensor_overrides.items():
        if sensor_name in sensor_types:
            sensor_types[sensor_name].update(override)
            sensor_types[sensor_name].pop("modbus_layout", None)
            sensor_types[sensor_name].pop("bacnet_layout", None)

    sensor_types.pop("SC001_safety_helmet", None)

    obsolete_attributes = (
        "beaconCount",
        "beaconTimestamp",
        "gpsTimestamp",
        "gpsCount",
        "gpsAltitude",
        "gpsRepeated",
        "beacon0_id",
        "beacon0_rssi",
        "beacon0_batteryLevel",
        "beacon0_batteryValid",
        "beacon0_flags",
        "beacon0_timeOffset",
        "beacon0_absoluteTime",
        "beacon0_scannedCount",
        "beacon1_id",
        "beacon1_flags",
        "beacon1_rssi",
        "beacon1_batteryLevel",
        "beacon1_batteryValid",
        "beacon1_timeOffset",
        "beacon1_absoluteTime",
        "beacon1_scannedCount",
        "beacon2_id",
        "beacon2_flags",
        "beacon2_rssi",
        "beacon2_batteryLevel",
        "beacon2_batteryValid",
        "beacon2_timeOffset",
        "beacon2_absoluteTime",
        "beacon2_scannedCount",
    )
    for attribute_name in obsolete_attributes:
        attributes.pop(attribute_name, None)

    return config_data


def load_uci_config(_file_path=None):
    config_snapshot_path = Path(_file_path) if _file_path else resolve_config_snapshot_path()
    if config_snapshot_path and config_snapshot_path.exists():
        return _apply_latest_track_projection_overrides(load_live_uci_config(config_snapshot_path))

    return _BUILTIN_SNAPSHOT


def _parse_int(value, default=0):
    if value in (None, ""):
        return default
    return int(value)


def _parse_float(value, default=0.0):
    if value in (None, ""):
        return default
    return float(value)


def get_global_defaults(config_data):
    globals_cfg = config_data.get("globals", {})
    return {
        "modbus_port": _parse_int(globals_cfg.get("default_modbus_tcp_port"), 502),
        "modbus_slave_id": _parse_int(globals_cfg.get("default_modbus_tcp_slave_id"), 2),
    }


def resolve_sensor_type_name(config_data, sensor_type_or_model):
    sensor_types = config_data.get("sensor_types", {})
    requested = sensor_type_or_model.casefold()
    for sensor_type_name, sensor in sensor_types.items():
        if str(sensor.get("model_name", "")).casefold() == requested:
            return sensor_type_name
    return SUPPORTED_SENSOR_MODELS.get(str(sensor_type_or_model).strip())


def get_sensor_display_name(config_data, sensor_type_name):
    sensor = config_data.get("sensor_types", {}).get(sensor_type_name, {})
    model_name = str(sensor.get("model_name", "")).strip()
    return model_name or sensor_type_name


def get_sensor_profile_version(config_data, sensor_type_name):
    sensor = config_data.get("sensor_types", {}).get(sensor_type_name, {})
    raw = str(sensor.get("version", "0")).strip()
    return int(raw) if raw.isdigit() else 0


def value_kind_from_data_type(data_type):
    normalized = str(data_type or "").strip().lower()
    if normalized == "bool":
        return "bool"
    if normalized == "float":
        return "float"
    if normalized == "string":
        return "string"
    if normalized == "binary":
        return "binary"
    if normalized in {"int", "uint", "timestamp"}:
        return "int"
    return normalized or "unknown"


def normalize_hash_scale(value):
    try:
        return format(float(value), ".9g")
    except (TypeError, ValueError):
        return "1"


def fnv1a32_update(hash_value, token):
    data = str(token or "").encode("utf-8") + b"\x1f"
    for byte in data:
        hash_value ^= byte
        hash_value = (hash_value * 16777619) & 0xFFFFFFFF
    return hash_value


def compute_modbus_layout_hash(layout, config_data=None, sensor_type_name=None):
    """Hash all Modbus holding-register fields by (name, json_key, kind, table, register_count,
    mapping_mode, scale) in field order.  Absolute offset is intentionally excluded — it is
    determined by field sequence + register_count values, so any reorder, insertion, or
    deletion is still detected. Also catches name and type changes in any field."""
    hash_value = 2166136261
    hash_value = fnv1a32_update(hash_value, "modbus")

    if config_data and sensor_type_name:
        sensor = config_data.get("sensor_types", {}).get(sensor_type_name)
        attributes_map = config_data.get("attributes", {})
        if sensor:
            for attribute_name in sensor.get("attributes", []):
                attribute = attributes_map.get(attribute_name, {})
                if attribute.get("modbus_enable") != "1" or attribute.get("modbus_table", "holding") != "holding":
                    continue
                try:
                    reg_count = int(attribute.get("modbus_register_count", 1) or 1)
                except (ValueError, TypeError):
                    reg_count = 1
                hash_value = fnv1a32_update(hash_value, attribute_name)
                hash_value = fnv1a32_update(hash_value, attribute.get("json_key", attribute_name))
                hash_value = fnv1a32_update(hash_value, value_kind_from_data_type(attribute.get("data_type")))
                hash_value = fnv1a32_update(hash_value, attribute.get("modbus_table", "holding"))
                hash_value = fnv1a32_update(hash_value, reg_count)
                hash_value = fnv1a32_update(hash_value, attribute.get("modbus_mapping_mode", "single"))
                hash_value = fnv1a32_update(hash_value, normalize_hash_scale(float(attribute.get("modbus_scale", 1.0) or 1.0)))
            return f"{hash_value:08X}"

    # Fallback: hash the provided layout directly
    for entry in layout:
        hash_value = fnv1a32_update(hash_value, entry.get("name", ""))
        hash_value = fnv1a32_update(hash_value, entry.get("json_key", ""))
        hash_value = fnv1a32_update(hash_value, value_kind_from_data_type(entry.get("data_type")))
        hash_value = fnv1a32_update(hash_value, entry.get("modbus_table", "holding"))
        hash_value = fnv1a32_update(hash_value, entry.get("register_count", 1))
        hash_value = fnv1a32_update(hash_value, entry.get("mapping_mode", entry.get("modbus_mapping_mode", "single")))
        hash_value = fnv1a32_update(hash_value, normalize_hash_scale(entry.get("scale", entry.get("modbus_scale", 1.0))))
    return f"{hash_value:08X}"


def get_attribute_definition(config_data, attribute_name):
    raw = config_data.get("attributes", {}).get(attribute_name, {})
    return {
        "name": attribute_name,
        "json_key": raw.get("json_key", attribute_name),
        "data_type": raw.get("data_type", "string"),
        "unit": raw.get("unit", ""),
        "decimal_places": _parse_int(raw.get("decimal_places"), -1),
        "modbus_enable": raw.get("modbus_enable") == "1",
        "modbus_table": raw.get("modbus_table", "holding"),
        "modbus_register_count": _parse_int(raw.get("modbus_register_count"), 1),
        "modbus_mapping_mode": raw.get("modbus_mapping_mode", "single"),
        "modbus_scale": _parse_float(raw.get("modbus_scale"), 1.0),
    }


def build_fixed_ds103_layout():
    fixed_entries = [
        ("online", "online", "bool", "none", 1, "single", 1.0, 0),
        ("lastOnlineTime", "lastOnlineTime", "timestamp", "second", 2, "big_endian", 1.0, 1),
        ("ds103ControlTarget", "ds103ControlTarget", "int", "none", 1, "single", 1.0, 3),
        ("ds103ControlState", "ds103ControlState", "bool", "none", 1, "single", 1.0, 4),
        ("ds103ControlMode", "ds103ControlMode", "int", "none", 1, "single", 1.0, 5),
        ("ds103DelaySeconds", "ds103DelaySeconds", "int", "seconds", 2, "big_endian", 1.0, 6),
        ("ds103ScheduleTimestamp", "ds103ScheduleTimestamp", "timestamp", "seconds", 2, "big_endian", 1.0, 8),
        ("ds103RepeatDaily", "ds103RepeatDaily", "bool", "none", 1, "single", 1.0, 10),
        ("lockState", "lockState", "int", "none", 1, "single", 1.0, 11),
        ("switch1State", "switch1State", "bool", "none", 1, "single", 1.0, 12),
        ("switch2State", "switch2State", "bool", "none", 1, "single", 1.0, 13),
        ("switch3State", "switch3State", "bool", "none", 1, "single", 1.0, 14),
        ("timestamp", "timestamp", "int", "seconds", 2, "single", 1.0, 15),
        ("switchTimerStatus", "switchTimerStatus", "int", "none", 2, "big_endian", 1.0, 17),
        ("timerCloseEnabled1", "timerCloseEnabled1", "bool", "none", 1, "single", 1.0, 19),
        ("timerOpenEnabled1", "timerOpenEnabled1", "bool", "none", 1, "single", 1.0, 20),
        ("timerCloseEnabled2", "timerCloseEnabled2", "bool", "none", 1, "single", 1.0, 21),
        ("timerOpenEnabled2", "timerOpenEnabled2", "bool", "none", 1, "single", 1.0, 22),
        ("timerCloseEnabled3", "timerCloseEnabled3", "bool", "none", 1, "single", 1.0, 23),
        ("timerOpenEnabled3", "timerOpenEnabled3", "bool", "none", 1, "single", 1.0, 24),
        ("timerLockEnabled", "timerLockEnabled", "bool", "none", 1, "single", 1.0, 25),
        ("timerUnlockEnabled", "timerUnlockEnabled", "bool", "none", 1, "single", 1.0, 26),
        ("mainVersion", "mainVersion", "string", "none", 32, "string", 1.0, 27),
        ("appVersion", "appVersion", "string", "none", 32, "string", 1.0, 59),
        ("hardwareVersion", "hardwareVersion", "string", "none", 32, "string", 1.0, 91),
        ("model", "model", "string", "none", 32, "string", 1.0, 123),
        ("rssi", "rssi", "int", "none", 1, "single", 1.0, 155),
        ("snr", "snr", "int", "none", 1, "single", 1.0, 156),
    ]

    layout = []
    for name, json_key, data_type, unit, register_count, mapping_mode, scale, offset in fixed_entries:
        layout.append(
            {
                "name": name,
                "json_key": json_key,
                "data_type": data_type,
                "unit": unit,
                "decimal_places": -1,
                "modbus_enable": True,
                "modbus_table": "holding",
                "modbus_register_count": register_count,
                "modbus_mapping_mode": mapping_mode,
                "modbus_scale": scale,
                "offset": offset,
                "register_count": register_count,
                "mapping_mode": mapping_mode,
                "scale": scale,
            }
        )
    return shift_modbus_layout_after_meta_header(layout)


def build_fixed_ds501_layout():
    fixed_entries = [
        ("online", "online", "bool", "none", 1, "single", 1.0, 0),
        ("lastOnlineTime", "lastOnlineTime", "timestamp", "second", 2, "big_endian", 1.0, 1),
        ("ds501ControlTarget", "ds501ControlTarget", "int", "none", 1, "single", 1.0, 3),
        ("ds501ControlState", "ds501ControlState", "bool", "none", 1, "single", 1.0, 4),
        ("ds501ControlMode", "ds501ControlMode", "int", "none", 1, "single", 1.0, 5),
        ("ds501DelaySeconds", "ds501DelaySeconds", "int", "seconds", 2, "big_endian", 1.0, 6),
        ("ds501ScheduleTimestamp", "ds501ScheduleTimestamp", "timestamp", "seconds", 2, "big_endian", 1.0, 8),
        ("ds501RepeatDaily", "ds501RepeatDaily", "bool", "none", 1, "single", 1.0, 10),
        ("switch", "switch", "bool", "none", 1, "single", 1.0, 11),
        ("lockState", "lockState", "int", "none", 1, "single", 1.0, 12),
        ("voltage", "voltage", "float", "volt", 1, "single", 10.0, 13),
        ("current", "current", "float", "ampere", 1, "single", 100.0, 14),
        ("activePower", "activePower", "float", "watt", 1, "single", 100.0, 15),
        ("energy", "energy", "float", "kilowatt_hour", 2, "big_endian", 100.0, 16),
        ("timestamp", "timestamp", "int", "seconds", 2, "single", 1.0, 18),
        ("timerCloseEnabled", "timerCloseEnabled", "bool", "none", 1, "single", 1.0, 20),
        ("timerOpenEnabled", "timerOpenEnabled", "bool", "none", 1, "single", 1.0, 21),
        ("timerLockEnabled", "timerLockEnabled", "bool", "none", 1, "single", 1.0, 22),
        ("timerUnlockEnabled", "timerUnlockEnabled", "bool", "none", 1, "single", 1.0, 23),
        ("mainVersion", "mainVersion", "string", "none", 32, "string", 1.0, 24),
        ("appVersion", "appVersion", "string", "none", 32, "string", 1.0, 56),
        ("hardwareVersion", "hardwareVersion", "string", "none", 32, "string", 1.0, 88),
        ("model", "model", "string", "none", 32, "string", 1.0, 120),
        ("rssi", "rssi", "int", "none", 1, "single", 1.0, 152),
        ("snr", "snr", "int", "none", 1, "single", 1.0, 153),
    ]

    layout = []
    for name, json_key, data_type, unit, register_count, mapping_mode, scale, offset in fixed_entries:
        layout.append(
            {
                "name": name,
                "json_key": json_key,
                "data_type": data_type,
                "unit": unit,
                "decimal_places": -1,
                "modbus_enable": True,
                "modbus_table": "holding",
                "modbus_register_count": register_count,
                "modbus_mapping_mode": mapping_mode,
                "modbus_scale": scale,
                "offset": offset,
                "register_count": register_count,
                "mapping_mode": mapping_mode,
                "scale": scale,
            }
        )
    return shift_modbus_layout_after_meta_header(layout)


def shift_modbus_layout_after_meta_header(layout):
    shifted = []
    for entry in layout:
        copied = dict(entry)
        copied["offset"] = int(copied.get("offset", 0)) + MODBUS_DEVICE_META_HEADER_REG_COUNT
        shifted.append(copied)
    return shifted


def needs_fixed_ds103_layout(config_data, sensor_type_name):
    if sensor_type_name != DS103_SENSOR_TYPE:
        return False

    sensor = config_data.get("sensor_types", {}).get(sensor_type_name, {})
    attributes = sensor.get("attributes", [])
    return (
        "ds103ControlTarget" not in attributes
        or "ds103ControlMode" not in attributes
        or "powerState" in attributes
        or "localTime" in attributes
    )


def needs_fixed_ds501_layout(config_data, sensor_type_name):
    if sensor_type_name != DS501_SENSOR_TYPE:
        return False

    sensor = config_data.get("sensor_types", {}).get(sensor_type_name, {})
    attributes = sensor.get("attributes", [])
    timestamp_before_energy = (
        "timestamp" in attributes
        and "energy" in attributes
        and attributes.index("timestamp") < attributes.index("energy")
    )
    return (
        "ds501ControlTarget" not in attributes
        or "ds501ControlMode" not in attributes
        or "switch" not in attributes
        or "powerState" in attributes
        or timestamp_before_energy
    )


def append_missing_ef5600_control_entries(layout):
    control_names = {
        "ef5600CommandCode",
        "ef5600SettingAddress",
        "ef5600SettingValueHigh",
        "ef5600SettingValueLow",
    }
    has_all_controls = all(any(entry.get("name") == name for entry in layout) for name in control_names)
    normalized = []
    for entry in layout:
        copied = dict(entry)
        if copied.get("name") == "powerState":
            copied["name"] = "switch"
            copied["json_key"] = "switch"
        normalized.append(copied)

    if has_all_controls:
        return normalized

    adjusted = []
    for entry in normalized:
        copied = dict(entry)
        if copied.get("offset", 0) >= 3:
            copied["offset"] = copied["offset"] + 4
        adjusted.append(copied)

    control_entries = [
        ("ef5600CommandCode", "ef5600CommandCode", 3, 0, 255),
        ("ef5600SettingAddress", "ef5600SettingAddress", 4, 0, 65535),
        ("ef5600SettingValueHigh", "ef5600SettingValueHigh", 5, 0, 255),
        ("ef5600SettingValueLow", "ef5600SettingValueLow", 6, 0, 255),
    ]
    injected = []
    inserted = False
    for entry in adjusted:
        if not inserted and entry.get("offset", 0) >= 7:
            for name, json_key, offset, min_value, max_value in control_entries:
                injected.append(
                    {
                        "name": name,
                        "json_key": json_key,
                        "data_type": "int",
                        "unit": "none",
                        "decimal_places": -1,
                        "modbus_enable": True,
                        "modbus_table": "holding",
                        "modbus_register_count": 1,
                        "modbus_mapping_mode": "single",
                        "modbus_scale": 1.0,
                        "min_value": min_value,
                        "max_value": max_value,
                        "offset": offset,
                        "register_count": 1,
                        "mapping_mode": "single",
                        "scale": 1.0,
                    }
                )
            inserted = True
        injected.append(entry)

    if not inserted:
        injected.extend(
            {
                "name": name,
                "json_key": json_key,
                "data_type": "int",
                "unit": "none",
                "decimal_places": -1,
                "modbus_enable": True,
                "modbus_table": "holding",
                "modbus_register_count": 1,
                "modbus_mapping_mode": "single",
                "modbus_scale": 1.0,
                "min_value": min_value,
                "max_value": max_value,
                "offset": offset,
                "register_count": 1,
                "mapping_mode": "single",
                "scale": 1.0,
            }
            for name, json_key, offset, min_value, max_value in control_entries
        )

    return injected


def build_modbus_layout(config_data, sensor_type_name):
    sensor = config_data.get("sensor_types", {}).get(sensor_type_name)
    if not sensor:
        return []

    if needs_fixed_ds103_layout(config_data, sensor_type_name):
        return build_fixed_ds103_layout()
    if needs_fixed_ds501_layout(config_data, sensor_type_name):
        return build_fixed_ds501_layout()

    predefined_layout = sensor.get("modbus_layout")
    if isinstance(predefined_layout, list) and predefined_layout:
        layout = [dict(entry) for entry in predefined_layout]
        if sensor_type_name == EF5600_SENSOR_TYPE:
            layout = append_missing_ef5600_control_entries(layout)
        return shift_modbus_layout_after_meta_header(layout)

    layout = []
    offset = 0
    for attribute_name in sensor.get("attributes", []):
        attr_def = get_attribute_definition(config_data, attribute_name)
        if not attr_def["modbus_enable"] or attr_def["modbus_table"] != "holding":
            continue

        entry = dict(attr_def)
        entry.update(
            {
                "offset": offset,
                "register_count": attr_def["modbus_register_count"],
                "mapping_mode": attr_def["modbus_mapping_mode"],
                "scale": attr_def["modbus_scale"],
            }
        )
        layout.append(entry)
        offset += entry["register_count"]

    if sensor_type_name == EF5600_SENSOR_TYPE:
        layout = append_missing_ef5600_control_entries(layout)
    return shift_modbus_layout_after_meta_header(layout)


def format_value(value, attr_def):
    if value is None:
        return "N/A"
    data_type = attr_def.get("data_type")
    if data_type == "float":
        decimal_places = attr_def.get("decimal_places", -1)
        if decimal_places >= 0:
            return f"{float(value):.{decimal_places}f}"
        return str(float(value))
    if data_type == "bool":
        return "true" if bool(value) else "false"
    return str(value)


def decode_modbus_registers(registers, attr_def):
    data_type = attr_def.get("data_type")
    mapping_mode = attr_def.get("mapping_mode", attr_def.get("modbus_mapping_mode", "single"))
    scale = float(attr_def.get("scale", attr_def.get("modbus_scale", 1)) or 1)

    try:
        if data_type in {"int", "uint"}:
            if len(registers) == 1:
                value = registers[0]
                if data_type == "int":
                    value = struct.unpack(">h", struct.pack(">H", value))[0]
                return value / scale
            if len(registers) == 2:
                packed = (registers[1] << 16) | registers[0] if "little_endian" in mapping_mode else (registers[0] << 16) | registers[1]
                if data_type == "int":
                    packed = struct.unpack(">i", struct.pack(">I", packed))[0]
                return packed / scale

        if data_type == "float":
            if len(registers) == 1:
                raw_value = struct.unpack(">h", struct.pack(">H", registers[0]))[0]
                return float(raw_value) / scale
            if len(registers) == 2:
                packed = (registers[1] << 16) | registers[0] if "little_endian" in mapping_mode else (registers[0] << 16) | registers[1]
                value = struct.unpack(">f", struct.pack(">I", packed))[0]
                if scale not in (0.0, 1.0):
                    value = value / scale
                return value

        if data_type == "bool":
            return registers[0] > 0

        if data_type == "timestamp":
            if len(registers) == 2:
                return (registers[1] << 16) | registers[0] if "little_endian" in mapping_mode else (registers[0] << 16) | registers[1]
            return registers[0]

        if data_type == "string":
            raw = bytearray()
            for register in registers:
                raw.extend(struct.pack(">H", register))
            return raw.decode("utf-8", errors="ignore").split("\x00")[0]

        if data_type == "binary":
            return "".join(f"{register:04X}" for register in registers)
    except Exception:
        return None

    return None


def get_technical_info(data_type, count, mapping_mode, scale):
    fmt_str = "Unknown"
    order_str = "Big-Endian"

    if data_type in ("int", "uint"):
        prefix = "UInt" if data_type == "uint" else "Int"
        if count == 1:
            fmt_str = f"{prefix}16"
        elif count == 2:
            fmt_str = f"{prefix}32"
        elif count == 4:
            fmt_str = f"{prefix}64"
    elif data_type == "float":
        if count == 1:
            fmt_str = "Int16(S)"
        elif count == 2:
            fmt_str = "Float32"
    elif data_type == "bool":
        fmt_str = "Bit/Bool"
    elif data_type == "string":
        fmt_str = f"String({count * 2}B)"
    elif data_type == "timestamp":
        fmt_str = "UnixTime"

    if mapping_mode == "little_endian":
        order_str = "Little(Swap)"
    elif mapping_mode in ("big_endian", "single"):
        order_str = "Big(ABCD)"
    elif mapping_mode == "string":
        order_str = "ASCII"

    f_scale = float(scale or 1)
    scale_str = "x1"
    if f_scale not in (0.0, 1.0):
        if f_scale >= 1:
            scale_str = f"/{int(f_scale)}" if float(f_scale).is_integer() else f"/{f_scale}"
        else:
            scale_str = f"x{1 / f_scale}"

    return fmt_str, order_str, scale_str


def read_holding_registers_compat(client, offset, count, slave_id):
    try:
        return client.read_holding_registers(offset, count=count, device_id=slave_id)
    except TypeError:
        pass

    try:
        return client.read_holding_registers(offset, count=count, slave=slave_id)
    except TypeError:
        pass

    try:
        return client.read_holding_registers(offset, count=count, unit=slave_id)
    except TypeError:
        pass

    try:
        return client.read_holding_registers(offset, count, slave=slave_id)
    except TypeError:
        pass

    try:
        return client.read_holding_registers(offset, count, unit=slave_id)
    except TypeError:
        pass

    raise RuntimeError("unable to find a compatible pymodbus read_holding_registers API")


def decode_string_registers(registers):
    chars = []
    for value in registers or []:
        chars.append(chr((int(value) >> 8) & 0xFF))
        chars.append(chr(int(value) & 0xFF))
    return "".join(chars).split("\x00", 1)[0].strip()


def read_remote_protocol_header(client, slave_id):
    response = read_holding_registers_compat(
        client,
        0,
        MODBUS_DEVICE_META_HEADER_REG_COUNT,
        slave_id,
    )
    if response.isError():
        return None
    registers = response.registers or []
    if len(registers) < MODBUS_DEVICE_META_HEADER_REG_COUNT:
        return None
    return {
        "layoutHash": decode_string_registers(registers[MODBUS_DEVICE_META_LAYOUT_HASH_OFFSET:MODBUS_DEVICE_META_LAYOUT_HASH_OFFSET + MODBUS_DEVICE_META_LAYOUT_HASH_REG_COUNT]),
        "profileVersion": (int(registers[MODBUS_DEVICE_META_PROFILE_VERSION_OFFSET]) << 16) | int(registers[MODBUS_DEVICE_META_PROFILE_VERSION_OFFSET + 1]),
    }


def main():
    parser = argparse.ArgumentParser(
        description="Modbus TCP reader for IoT Hub sensor mappings",
        epilog=HELP_EXAMPLES,
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser.add_argument("--ip", type=str, default="127.0.0.1", help="Gateway IP address")
    parser.add_argument("--port", type=int, help="Modbus TCP port")
    parser.add_argument("--slaveId", dest="slaveId", type=int, help="Modbus slave ID")
    parser.add_argument("--sensorType", dest="sensorType", required=True, help="Sensor model name only, for example AN-303 or DS-501")
    parser.add_argument("--attribute", action="append", help="Optional attribute filter, repeatable")
    args = parser.parse_args()

    config_data = load_uci_config()
    defaults = get_global_defaults(config_data)
    sensor_type = resolve_sensor_type_name(config_data, args.sensorType)
    if not sensor_type:
        print(f"Error: Sensor model '{args.sensorType}' was not found.")
        sys.exit(1)

    register_plan = build_modbus_layout(config_data, sensor_type)

    if not register_plan:
        print(f"Error: No Modbus holding-register mapping found for '{sensor_type}'.")
        sys.exit(1)

    port = args.port or defaults["modbus_port"]
    slave_id = args.slaveId or defaults["modbus_slave_id"]
    attribute_filter = {name.casefold() for name in args.attribute or []}

    sensor_label = get_sensor_display_name(config_data, sensor_type)
    print(f"Target: {args.ip}:{port} | Slave ID: {slave_id} | Sensor: {sensor_label}")
    print("=" * 160)
    print(
        f"{'Attribute':<24} | {'Addr':<6} | {'FC':<3} | {'Format':<10} | {'Order':<12} | "
        f"{'Cnt':<3} | {'Scale':<8} | {'Raw(Hex)':<19} | {'Value':<18} | {'Unit'}"
    )
    print("-" * 160)

    client = ModbusTcpClient(args.ip, port=port, timeout=3.0)
    if not client.connect():
        print(f"Connection Failed: Unable to connect to {args.ip}:{port}")
        sys.exit(1)

    try:
        expected_version = get_sensor_profile_version(config_data, sensor_type)
        expected_layout_hash = compute_modbus_layout_hash(register_plan, config_data, sensor_type)
        remote_header = read_remote_protocol_header(client, slave_id)
        if expected_version or expected_layout_hash:
            if not remote_header:
                print(
                    "Error: Gateway service did not expose a valid fixed Modbus protocol header at registers "
                    f"0-{MODBUS_DEVICE_META_HEADER_REG_COUNT - 1}. "
                    "The running iot_hub service is likely too old for this script."
                )
                sys.exit(2)
            if remote_header["layoutHash"] != expected_layout_hash:
                print(
                    f"Error: Modbus layout hash mismatch for {sensor_label}. "
                    f"Script expects {expected_layout_hash}, gateway exposes {remote_header['layoutHash']}. "
                    "Please update the Python scripts or restart iot_hub with the matching protocol mapping."
                )
                sys.exit(2)
            if expected_version and remote_header["profileVersion"] != expected_version:
                print(
                    f"Error: Profile version mismatch for {sensor_label}. "
                    f"Script expects {expected_version}, gateway exposes {remote_header['profileVersion']}. "
                    "Please update the Python scripts or restart iot_hub with the matching protocol mapping."
                )
                sys.exit(2)

        for entry in register_plan:
            if attribute_filter and entry["name"].casefold() not in attribute_filter and entry["json_key"].casefold() not in attribute_filter:
                continue

            attr_name = entry["name"]
            offset = int(entry["offset"])
            count = int(entry["register_count"])
            mapping_mode = entry.get("mapping_mode", "single")
            scale = float(entry.get("scale", 1) or 1)
            data_type = entry.get("data_type", "string")
            unit = entry.get("unit", "")
            fc = 3

            fmt_str, order_str, scale_str = get_technical_info(data_type, count, mapping_mode, scale)
            response = read_holding_registers_compat(client, offset, count, slave_id)

            if response.isError():
                error_msg = "Err"
                if hasattr(response, "exception_code"):
                    if response.exception_code == 2:
                        error_msg = "IllegalAddr"
                    elif response.exception_code == 3:
                        error_msg = "IllegalVal"
                    elif response.exception_code == 4:
                        error_msg = "SlaveFail"
                    else:
                        error_msg = f"ExCode({response.exception_code})"
                elif hasattr(response, "stringify"):
                    try:
                        error_msg = response.stringify()
                    except Exception:
                        pass
                else:
                    error_msg = str(response)

                print(
                    f"{attr_name:<24} | {offset:<6} | {fc:02d}  | {fmt_str:<10} | {order_str:<12} | "
                    f"{count:<3} | {scale_str:<8} | {error_msg:<19} | {'N/A':<18} |"
                )
                continue

            registers = response.registers
            raw_hex = " ".join(f"{value:04X}" for value in registers[:4])
            if len(registers) > 4:
                raw_hex += " ..."

            decoded = decode_modbus_registers(registers, entry)
            value_str = format_value(decoded, entry) if decoded is not None else "Err"

            print(
                f"{attr_name:<24} | {offset:<6} | {fc:02d}  | {fmt_str:<10} | {order_str:<12} | "
                f"{count:<3} | {scale_str:<8} | {raw_hex:<19} | {value_str:<18} | {unit}"
            )
    finally:
        client.close()


if __name__ == "__main__":
    main()
