├── .dockerignore
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request
│ └── help_wanted.md
└── workflows
│ ├── close_issue.yml
│ ├── codeql-analysis.yml
│ ├── issue_creation.yml
│ ├── reopened_issue.yml
│ └── update_issue_in_jira.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── MANIFEST.in
├── README.md
├── build_latest_docker.sh
├── docker
├── Dockerfile
└── docker-compose.yml
├── for_build
├── DEBIAN
│ ├── postinst
│ ├── preinst
│ └── pydist-overrides
├── etc
│ └── systemd
│ │ └── system
│ │ └── thingsboard-gateway.service
└── var
│ └── log
│ └── thingsboard-gateway
│ ├── connector.log
│ ├── converter.log
│ ├── database.log
│ ├── extension.log
│ ├── service.log
│ ├── storage.log
│ └── tb_connection.log
├── generate_deb_package.sh
├── make_packages.sh
├── requirements.txt
├── setup.py
├── tests
├── __init__.py
├── base_test.py
├── blackbox
│ ├── __init__.py
│ ├── connectors
│ │ ├── __init__.py
│ │ ├── modbus
│ │ │ ├── __init__.py
│ │ │ ├── test_modbus_attributes_updates.py
│ │ │ ├── test_modbus_rpc.py
│ │ │ └── test_modbus_uplink_messages.py
│ │ └── opcua
│ │ │ ├── __init__.py
│ │ │ ├── test_base_opcua.py
│ │ │ ├── test_opcua_attributes_updates.py
│ │ │ ├── test_opcua_rpc.py
│ │ │ └── test_opcua_uplink_messages.py
│ ├── data
│ │ ├── modbus
│ │ │ ├── configs
│ │ │ │ ├── attrs_update_configs
│ │ │ │ │ ├── attrs_update_coils_registers_big.json
│ │ │ │ │ ├── attrs_update_coils_registers_little.json
│ │ │ │ │ ├── attrs_update_discrete_input_big.json
│ │ │ │ │ ├── attrs_update_discrete_input_little.json
│ │ │ │ │ ├── attrs_update_holding_registers_big.json
│ │ │ │ │ ├── attrs_update_holding_registers_little.json
│ │ │ │ │ ├── attrs_update_input_registers_big.json
│ │ │ │ │ └── attrs_update_input_registers_little.json
│ │ │ │ ├── default_modbus_config.json
│ │ │ │ ├── initial_modbus_uplink_converter_report_strategy_on_change.json
│ │ │ │ ├── initial_modbus_uplink_converter_report_strategy_on_change_or_report_period_on_period_factor.json
│ │ │ │ ├── initial_modbus_uplink_converter_report_strategy_on_received.json
│ │ │ │ ├── initial_modbus_uplink_converter_report_strategy_on_report_period.json
│ │ │ │ ├── rpc_configs
│ │ │ │ │ ├── coils_reading_rpc_big.json
│ │ │ │ │ ├── coils_reading_rpc_little.json
│ │ │ │ │ ├── coils_writing_rpc_big.json
│ │ │ │ │ ├── coils_writing_rpc_little.json
│ │ │ │ │ ├── discrete_inputs_reading_rpc_big.json
│ │ │ │ │ ├── discrete_inputs_reading_rpc_little.json
│ │ │ │ │ ├── discrete_inputs_writing_rpc_big.json
│ │ │ │ │ ├── discrete_inputs_writing_rpc_little.json
│ │ │ │ │ ├── holding_registers_reading_rpc_big.json
│ │ │ │ │ ├── holding_registers_reading_rpc_little.json
│ │ │ │ │ ├── holding_registers_writing_rpc_big.json
│ │ │ │ │ ├── holding_registers_writing_rpc_little.json
│ │ │ │ │ ├── input_registers_reading_rpc_big.json
│ │ │ │ │ ├── input_registers_reading_rpc_little.json
│ │ │ │ │ ├── input_registers_writing_rpc_big.json
│ │ │ │ │ └── input_registers_writing_rpc_little.json
│ │ │ │ └── uplink_configs
│ │ │ │ │ ├── modbus_uplink_converter_coils_reading_big.json
│ │ │ │ │ ├── modbus_uplink_converter_coils_reading_little.json
│ │ │ │ │ ├── modbus_uplink_converter_discrete_input_reading_big.json
│ │ │ │ │ ├── modbus_uplink_converter_discrete_input_reading_little.json
│ │ │ │ │ ├── modbus_uplink_converter_holding_registers_reading_big.json
│ │ │ │ │ ├── modbus_uplink_converter_holding_registers_reading_little.json
│ │ │ │ │ ├── modbus_uplink_converter_input_registers_reading_big.json
│ │ │ │ │ └── modbus_uplink_converter_input_registers_reading_little.json
│ │ │ ├── modbus_rename_configs
│ │ │ │ ├── default_modbus_config.json
│ │ │ │ ├── input_registers_writing_rpc_big.json
│ │ │ │ └── modbus_uplink_converter_input_registers_reading_little.json
│ │ │ └── test_values
│ │ │ │ ├── attrs_update
│ │ │ │ ├── discrete_and_coils_registers_values_big.json
│ │ │ │ ├── discrete_and_coils_registers_values_little.json
│ │ │ │ ├── holding_registers_values_big.json
│ │ │ │ ├── holding_registers_values_little.json
│ │ │ │ ├── input_registers_values_big.json
│ │ │ │ └── input_registers_values_little.json
│ │ │ │ ├── default_slave_values.json
│ │ │ │ ├── rpc
│ │ │ │ ├── discrete_and_coils_registers_values_reading_big.json
│ │ │ │ ├── discrete_and_coils_registers_values_reading_little.json
│ │ │ │ ├── discrete_and_coils_registers_values_writing_big.json
│ │ │ │ ├── discrete_and_coils_registers_values_writing_little.json
│ │ │ │ ├── holding_registers_values_reading_big.json
│ │ │ │ ├── holding_registers_values_reading_little.json
│ │ │ │ ├── holding_registers_values_writing_big.json
│ │ │ │ ├── holding_registers_values_writing_little.json
│ │ │ │ ├── input_registers_values_reading_big.json
│ │ │ │ ├── input_registers_values_reading_little.json
│ │ │ │ ├── input_registers_values_writing_big.json
│ │ │ │ └── input_registers_values_writing_little.json
│ │ │ │ └── uplink
│ │ │ │ ├── discrete_and_coils_registers_values_big.json
│ │ │ │ ├── discrete_and_coils_registers_values_little.json
│ │ │ │ ├── holding_registers_values_big.json
│ │ │ │ ├── holding_registers_values_little.json
│ │ │ │ ├── input_registers_values_big.json
│ │ │ │ └── input_registers_values_little.json
│ │ └── opcua
│ │ │ ├── configs
│ │ │ ├── attrs_update_configs
│ │ │ │ └── attrs_update_node.json
│ │ │ ├── default_opcua_config.json
│ │ │ ├── rpc_configs
│ │ │ │ ├── rpc_get_method.json
│ │ │ │ ├── rpc_server_method.json
│ │ │ │ └── rpc_set_method.json
│ │ │ └── uplink_configs
│ │ │ │ ├── different_node_finding_methods_config_b.json
│ │ │ │ ├── different_node_finding_methods_config_g.json
│ │ │ │ ├── different_node_finding_methods_config_i.json
│ │ │ │ ├── different_node_finding_methods_config_path.json
│ │ │ │ └── different_node_finding_methods_config_s.json
│ │ │ └── test_values
│ │ │ ├── attrs_update
│ │ │ ├── attrs_update_connection_lost_node.json
│ │ │ ├── attrs_update_node_values.json
│ │ │ └── attrs_update_restart_node_values.json
│ │ │ ├── default_node_values.json
│ │ │ ├── rpc
│ │ │ ├── rpc_get_method_values.json
│ │ │ ├── rpc_server_method_values.json
│ │ │ └── rpc_set_method_values.json
│ │ │ └── uplink
│ │ │ └── different_node_finding_methods_values.json
│ └── service
│ │ ├── __init__.py
│ │ └── test_device_renaming.py
├── docker-compose.yml
├── integration
│ ├── __init__.py
│ ├── connectors
│ │ ├── __init__.py
│ │ ├── can
│ │ │ ├── __init__.py
│ │ │ └── test_can_connector.py
│ │ ├── connector_integration_base_test.py
│ │ ├── modbus
│ │ │ ├── __init__.py
│ │ │ └── test_modbus_connector.py
│ │ ├── odbc
│ │ │ ├── __init__.py
│ │ │ └── test_odbc_connector.py
│ │ └── opcua
│ │ │ ├── __init__.py
│ │ │ ├── helpers.py
│ │ │ ├── opcua_test_server.py
│ │ │ ├── test_integration.py
│ │ │ └── test_opcua_connector.py
│ ├── data
│ │ ├── __init__.py
│ │ ├── can
│ │ │ ├── attribute_updates.json
│ │ │ ├── multiple_polling.json
│ │ │ ├── polling_always.json
│ │ │ ├── polling_once.json
│ │ │ ├── rpc.json
│ │ │ └── ts_and_attr.json
│ │ ├── gateway
│ │ │ ├── gateway.json
│ │ │ ├── logs.json
│ │ │ └── mqtt.json
│ │ ├── modbus
│ │ │ ├── __init__.py
│ │ │ ├── modbus_attribute_updates.json
│ │ │ ├── modbus_attributes.json
│ │ │ ├── modbus_rpc.json
│ │ │ └── modbus_server.py
│ │ ├── odbc
│ │ │ ├── odbc_attributes.json
│ │ │ ├── odbc_iterator.json
│ │ │ ├── odbc_rpc.json
│ │ │ ├── odbc_timeseries.json
│ │ │ ├── postgres.sql
│ │ │ └── sqlite3.db
│ │ └── opcua
│ │ │ ├── connection_test.json
│ │ │ └── opcua_test_connection.json
│ ├── integration_base_test.py
│ └── service
│ │ ├── __init__.py
│ │ └── test_gateway_client.py
├── requirements.txt
├── start_tests.sh
├── test_utils
│ ├── __init__.py
│ └── gateway_device_util.py
├── tests.py
└── unit
│ ├── BaseUnitTest.py
│ ├── __init__.py
│ ├── connectors
│ ├── __init__.py
│ ├── bacnet
│ │ ├── __init__.py
│ │ └── test_device.py
│ ├── ftp
│ │ ├── __init__.py
│ │ ├── data
│ │ │ ├── anonym_type
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ ├── attribute_updates
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ └── basic_type
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ └── test_ftp_backward_compatibility_adapter.py
│ ├── mqtt
│ │ ├── __init__.py
│ │ ├── data
│ │ │ ├── attribute_requests
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ ├── attribute_updates
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ ├── connect_requests
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ ├── disconnect_requests
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ ├── mapping
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ │ └── server_side_rpc
│ │ │ │ ├── new_config.json
│ │ │ │ └── old_config.json
│ │ └── test_mqtt_backward_compatibility_adapter.py
│ ├── opcua
│ │ ├── __init__.py
│ │ └── test_check_path.py
│ └── socket
│ │ ├── __init__.py
│ │ ├── data
│ │ ├── new_config.json
│ │ └── old_config.json
│ │ └── test_socket_backward_compatibility_adapter.py
│ ├── converters
│ ├── __init__.py
│ ├── can
│ │ ├── __init__.py
│ │ ├── test_bytes_can_downlink_converter.py
│ │ └── test_bytes_can_uplink_converter.py
│ ├── modbus
│ │ ├── __init__.py
│ │ └── test_bytes_modbus_uplink_converter.py
│ ├── mqtt
│ │ ├── __init__.py
│ │ └── test_mqtt_json_uplink_converter.py
│ ├── odbc
│ │ ├── __init__.py
│ │ └── test_odbc_uplink_converter.py
│ └── request
│ │ ├── __init__.py
│ │ └── test_request_json_uplink_converter.py
│ ├── data
│ └── __init__.py
│ └── service
│ ├── __init__.py
│ ├── test_storage.py
│ └── test_ts_format_resolver.py
├── thingsboard-gateway.spec
└── thingsboard_gateway
├── __init__.py
├── config
├── bacnet.json
├── ble.json
├── can.json
├── custom_serial.json
├── ftp.json
├── knx.json
├── list.json
├── logs.json
├── modbus.json
├── modbus_serial.json
├── mqtt.json
├── ocpp.json
├── odbc.json
├── opcua.json
├── request.json
├── rest.json
├── snmp.json
├── socket.json
├── statistics
│ ├── statistics_linux.json
│ ├── statistics_macos.json
│ └── statistics_windows.json
├── tb_gateway.json
└── xmpp.json
├── connectors
├── __init__.py
├── bacnet
│ ├── __init__.py
│ ├── application.py
│ ├── application_service_access_point.py
│ ├── backward_compatibility_adapter.py
│ ├── bacnet_connector.py
│ ├── bacnet_converter.py
│ ├── bacnet_uplink_converter.py
│ ├── device.py
│ └── entities
│ │ ├── __init__.py
│ │ ├── bacnet_device_details.py
│ │ ├── device_info.py
│ │ ├── device_object_config.py
│ │ ├── routers.py
│ │ └── uplink_converter_config.py
├── ble
│ ├── __init__.py
│ ├── ble_connector.py
│ ├── ble_uplink_converter.py
│ ├── bytes_ble_uplink_converter.py
│ ├── device.py
│ ├── error_handler.py
│ └── hex_bytes_ble_uplink_converter.py
├── can
│ ├── __init__.py
│ ├── bytes_can_downlink_converter.py
│ ├── bytes_can_uplink_converter.py
│ ├── can_connector.py
│ └── can_converter.py
├── connector.py
├── converter.py
├── ftp
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── file.py
│ ├── ftp_connector.py
│ ├── ftp_converter.py
│ ├── ftp_uplink_converter.py
│ └── path.py
├── knx
│ ├── __init__.py
│ ├── entities
│ │ ├── __init__.py
│ │ ├── client_config.py
│ │ ├── device.py
│ │ └── gateways_scanner.py
│ ├── knx_connector.py
│ ├── knx_converter.py
│ └── knx_uplink_converter.py
├── modbus
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── bytes_modbus_downlink_converter.py
│ ├── bytes_modbus_uplink_converter.py
│ ├── constants.py
│ ├── entities
│ │ ├── __init__.py
│ │ ├── bytes_downlink_converter_config.py
│ │ ├── bytes_uplink_converter_config.py
│ │ ├── clients.py
│ │ └── master.py
│ ├── modbus_connector.py
│ ├── modbus_converter.py
│ ├── server.py
│ └── slave.py
├── mqtt
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── bytes_mqtt_uplink_converter.py
│ ├── json_mqtt_uplink_converter.py
│ ├── mqtt_connector.py
│ ├── mqtt_decorators.py
│ └── mqtt_uplink_converter.py
├── ocpp
│ ├── __init__.py
│ ├── charge_point.py
│ ├── ocpp_connector.py
│ ├── ocpp_converter.py
│ └── ocpp_uplink_converter.py
├── odbc
│ ├── __init__.py
│ ├── odbc_connector.py
│ ├── odbc_converter.py
│ └── odbc_uplink_converter.py
├── opcua
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── device.py
│ ├── opcua_connector.py
│ ├── opcua_converter.py
│ └── opcua_uplink_converter.py
├── request
│ ├── __init__.py
│ ├── json_request_downlink_converter.py
│ ├── json_request_uplink_converter.py
│ ├── request_connector.py
│ ├── request_converter.py
│ └── request_uplink_converter.py
├── rest
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── json_rest_downlink_converter.py
│ ├── json_rest_uplink_converter.py
│ ├── rest_connector.py
│ ├── rest_converter.py
│ └── ssl_generator.py
├── snmp
│ ├── __init__.py
│ ├── snmp_connector.py
│ ├── snmp_downlink_converter.py
│ └── snmp_uplink_converter.py
├── socket
│ ├── __init__.py
│ ├── backward_compatibility_adapter.py
│ ├── bytes_socket_uplink_converter.py
│ ├── socket_connector.py
│ ├── socket_decorators.py
│ └── socket_uplink_converter.py
└── xmpp
│ ├── __init__.py
│ ├── device.py
│ ├── xmpp_connector.py
│ ├── xmpp_converter.py
│ └── xmpp_uplink_converter.py
├── extensions
├── __init__.py
├── bacnet
│ └── __init__.py
├── bacnet_old
│ └── __init__.py
├── ble
│ └── __init__.py
├── can
│ └── __init__.py
├── ftp
│ └── __init__.py
├── knx
│ └── __init__.py
├── modbus
│ └── __init__.py
├── modbus_old
│ └── __init__.py
├── mqtt
│ ├── __init__.py
│ └── custom_mqtt_uplink_converter.py
├── ocpp
│ └── __init__.py
├── odbc
│ └── __init__.py
├── opcua
│ └── __init__.py
├── request
│ └── __init__.py
├── rest
│ └── __init__.py
├── serial
│ ├── __init__.py
│ ├── custom_serial_connector.py
│ ├── custom_serial_downlink_converter.py
│ └── custom_serial_uplink_converter.py
├── snmp
│ └── __init__.py
├── socket
│ └── __init__.py
└── xmpp
│ └── __init__.py
├── gateway
├── __init__.py
├── configuration_wizard.py
├── constant_enums.py
├── constants.py
├── device_filter.py
├── entities
│ ├── __init__.py
│ ├── attributes.py
│ ├── converted_data.py
│ ├── datapoint_key.py
│ ├── device_event_pack.py
│ ├── report_strategy_config.py
│ └── telemetry_entry.py
├── grpc_service
│ ├── __init__.py
│ ├── grpc_connector.py
│ ├── grpc_downlink_converter.py
│ ├── grpc_uplink_converter.py
│ ├── tb_grpc_manager.py
│ └── tb_grpc_server.py
├── hot_reloader.py
├── proto
│ ├── __init__.py
│ ├── messages.proto
│ ├── messages_pb2.py
│ └── messages_pb2_grpc.py
├── report_strategy
│ ├── __init__.py
│ ├── report_strategy_data_cache.py
│ └── report_strategy_service.py
├── shell
│ ├── __init__.py
│ ├── proxy.py
│ └── shell.py
├── statistics
│ ├── __init__.py
│ ├── configs.py
│ ├── decorators.py
│ ├── service_functions.py
│ └── statistics_service.py
├── tb_client.py
└── tb_gateway_service.py
├── grpc_connectors
├── __init__.py
├── gw_grpc_client.py
├── gw_grpc_connector.py
├── gw_grpc_msg_creator.py
├── gw_msg_callbacks.py
├── modbus
│ ├── __init__.py
│ ├── bytes_modbus_uplink_converter.py
│ ├── modbus_connector.py
│ └── slave.py
├── mqtt
│ ├── __init__.py
│ ├── bytes_mqtt_uplink_converter.py
│ ├── json_mqtt_uplink_converter.py
│ └── mqtt_connector.py
├── opcua
│ ├── __init__.py
│ ├── opcua_connector.py
│ └── opcua_uplink_converter.py
└── socket
│ ├── __init__.py
│ ├── bytes_socket_uplink_converter.py
│ └── socket_connector.py
├── storage
├── __init__.py
├── event_storage.py
├── file
│ ├── __init__.py
│ ├── event_storage_files.py
│ ├── event_storage_reader.py
│ ├── event_storage_reader_pointer.py
│ ├── event_storage_writer.py
│ ├── file_event_storage.py
│ └── file_event_storage_settings.py
├── memory
│ ├── __init__.py
│ └── memory_event_storage.py
└── sqlite
│ ├── __init__.py
│ ├── database.py
│ ├── database_connector.py
│ ├── sqlite_event_storage.py
│ └── storage_settings.py
├── tb_gateway.py
├── tb_utility
├── __init__.py
├── tb_gateway_remote_configurator.py
├── tb_handler.py
├── tb_loader.py
├── tb_logger.py
├── tb_remote_shell.py
├── tb_rotating_file_handler.py
├── tb_updater.py
└── tb_utility.py
└── version.py
/.dockerignore:
--------------------------------------------------------------------------------
1 | # ignore everyhting
2 | *
3 |
4 | # except the following
5 | !/thingsboard_gateway/
6 | !LICENSE
7 | !README.md
8 | !setup.py
9 | !requirements.txt
10 |
11 | # ignore on every level
12 | **/__pycache__/
13 | **/*.py[cod]
14 | **/logs/
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]"
5 | labels: bug
6 | assignees: imbeacon, samson0v
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | Clear and concise description of what the bug is.
12 |
13 | **Connector name (If bug in the some connector):**
14 | [e.g. OPC-UA Connector]
15 |
16 | **Error traceback (If available):**
17 | ```
18 | 'deviceName'
19 | Traceback (most recent call last):
20 | File "", line 2, in
21 | KeyError: 'deviceName'
22 | ```
23 |
24 | **Versions (please complete the following information):**
25 | - OS: [e.g. Ubuntu 18.04]
26 | - Thingsboard IoT Gateway version [e.g. 2.0]
27 | - Python version[e.g. 3.7]
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: If you have some suggestion about improvemnts or optimization
4 | title: "[Feature]"
5 | labels: feature
6 | assignees: imbeacon, samson0v
7 |
8 | ---
9 |
10 | **Describe the feature**
11 | Create a description of your idea and describe use cases where this feature can be useful.
12 |
13 |
14 | **Connector name (If you want to improve some connector/converter):**
15 | [e.g. MQTT Connector]
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/help_wanted.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Help wanted
3 | about: If you have some issues with configuration
4 | title: "[HELP]"
5 | labels: help wanted
6 | assignees: imbeacon, samson0v
7 |
8 | ---
9 |
10 | **Describe the issue**
11 | Create description about your issue, and your actions to solve it.
12 |
13 |
14 | **Configuration** (Attach your configuration file)
15 | **Notate: Remove Access token from file if you want to attach a tb_gateway.yaml**
16 |
17 |
18 | **Connector name (If you need help with some connector/converter):**
19 | [e.g. MQTT Connector]
20 |
21 |
22 | **Error traceback (If it was raised):**
23 | ```
24 | 'deviceName'
25 | Traceback (most recent call last):
26 | File "", line 2, in
27 | KeyError: 'deviceName'
28 | ```
29 |
30 |
31 | **Versions (please complete the following information):**
32 | - OS: [e.g. Ubuntu 20.04]
33 | - Thingsboard IoT Gateway version [e.g. 3.0.1]
34 | - Python version[e.g. 3.9]
35 |
--------------------------------------------------------------------------------
/.github/workflows/close_issue.yml:
--------------------------------------------------------------------------------
1 | on:
2 | issues:
3 | types:
4 | - closed
5 |
6 | name: Move ticket to closed
7 |
8 | jobs:
9 | close-ticket-in-jira:
10 | if: ${{ !github.event.issue.pull_request }}
11 | name: Close ticket
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Login
15 | uses: atlassian/gajira-login@master
16 | env:
17 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
18 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
19 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
20 |
21 | - name: Find Comment
22 | uses: peter-evans/find-comment@v2
23 | id: find_comment
24 | with:
25 | issue-number: ${{ github.event.issue.number }}
26 | comment-author: 'github-actions[bot]'
27 | direction: first
28 | nth: 0
29 |
30 | - name: Find Jira ticket
31 | if: steps.find_comment.outputs.comment-id != ''
32 | id: find_ticket
33 | uses: atlassian/gajira-find-issue-key@v3
34 | with:
35 | string: ${{ steps.find_comment.outputs.comment-body }}
36 |
37 | - name: Update Jira ticket
38 | if: steps.find_ticket.outputs.issue != ''
39 | uses: atlassian/gajira-comment@v3
40 | with:
41 | issue: ${{ steps.find_ticket.outputs.issue }}
42 | comment: |
43 | Github issue was closed by *${{ github.event.sender.login }}*
44 |
45 | - name: Move to Done
46 | if: steps.find_ticket.outputs.issue != ''
47 | id: transition
48 | uses: atlassian/gajira-transition@v3
49 | with:
50 | issue: ${{ steps.find_ticket.outputs.issue }}
51 | transition: "Closed"
52 |
--------------------------------------------------------------------------------
/.github/workflows/reopened_issue.yml:
--------------------------------------------------------------------------------
1 | on:
2 | issues:
3 | types:
4 | - reopened
5 |
6 | name: Move ticket if it was reopened
7 |
8 | jobs:
9 | close-ticket-in-jira:
10 | if: ${{ !github.event.issue.pull_request }}
11 | name: Move ticket if reopened
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Login
15 | uses: atlassian/gajira-login@master
16 | env:
17 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
18 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
19 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
20 |
21 | - name: Find Comment
22 | uses: peter-evans/find-comment@v2
23 | id: find_comment
24 | with:
25 | issue-number: ${{ github.event.issue.number }}
26 | comment-author: 'github-actions[bot]'
27 | direction: first
28 | nth: 0
29 |
30 | - name: Find Jira ticket
31 | if: steps.find_comment.outputs.comment-id != ''
32 | id: find_ticket
33 | uses: atlassian/gajira-find-issue-key@v3
34 | with:
35 | string: ${{ steps.find_comment.outputs.comment-body }}
36 |
37 | - name: Update Jira ticket
38 | if: steps.find_ticket.outputs.issue != ''
39 | uses: atlassian/gajira-comment@v3
40 | with:
41 | issue: ${{ steps.find_ticket.outputs.issue }}
42 | comment: |
43 | Github issue was reopened by *${{ github.event.sender.login }}*
44 |
45 | - name: Move to Backlog
46 | if: steps.find_ticket.outputs.issue != ''
47 | id: transition_to_backlog
48 | uses: atlassian/gajira-transition@v3
49 | with:
50 | issue: ${{ steps.find_ticket.outputs.issue }}
51 | transition: "task in backlog"
52 |
53 | - name: Move to Backlog
54 | if: steps.find_ticket.outputs.issue != ''
55 | id: transition_to_todo
56 | uses: atlassian/gajira-transition@v3
57 | with:
58 | issue: ${{ steps.find_ticket.outputs.issue }}
59 | transition: "Admin permissions only"
60 |
61 |
--------------------------------------------------------------------------------
/.github/workflows/update_issue_in_jira.yml:
--------------------------------------------------------------------------------
1 | on:
2 | issue_comment:
3 | types:
4 | - created
5 |
6 | name: Create a comment for ticket in Jira
7 |
8 | jobs:
9 | create-comment-for-ticket-in-jira:
10 | if: ${{ !github.event.issue.pull_request }}
11 | name: Ticket comment creation
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Login
15 | uses: atlassian/gajira-login@master
16 | env:
17 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
18 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
19 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
20 |
21 | - name: Find Comment
22 | uses: peter-evans/find-comment@v2
23 | id: find_comment
24 | with:
25 | issue-number: ${{ github.event.issue.number }}
26 | comment-author: 'github-actions[bot]'
27 | direction: first
28 | nth: 0
29 |
30 | - name: Find Jira ticket
31 | if: steps.find_comment.outputs.comment-id != ''
32 | id: find_ticket
33 | uses: atlassian/gajira-find-issue-key@v3
34 | with:
35 | string: ${{ steps.find_comment.outputs.comment-body }}
36 |
37 | - name: Update Jira ticket
38 | if: steps.find_ticket.outputs.issue != ''
39 | uses: atlassian/gajira-comment@v3
40 | with:
41 | issue: ${{ steps.find_ticket.outputs.issue }}
42 | comment: |
43 | Github issue was commented by *${{ github.event.comment.user.login }}*:
44 |
45 | ${{ github.event.comment.body }}
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | thingsboard_gateway/venv/
2 | thingsboard_gateway/logs/*
3 | thingsboard_gateway/config/connected_devices.json
4 | thingsboard_gateway/storage/data/
5 | .idea/
6 | .vscode/
7 | /build/
8 | /deb_dist/
9 | /dist/
10 | *.gz
11 | /logs/
12 | *.deb
13 | *.rpm
14 | /*.egg-info/
15 | /data/
16 | /logs/
17 | __pycache__
18 | /thingsboard_gateway/config/
19 | venv
20 | .venv
21 | .env
22 | /for_build/etc/thingsboard-gateway/config/
23 | /thingsboard_gateway/logs/
24 | /tests/storage/
25 | /tests/blackbox/connectors/opcua/_trial_temp/
26 | /tests/blackbox/connectors/modbus/_trial_temp/
27 | *.DS_Store
28 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "tb_mqtt_client"]
2 | path = tb_mqtt_client
3 | url = https://github.com/thingsboard/thingsboard-python-client-sdk.git
4 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | graft thingsboard_gateway/config
2 | include LICENSE
3 |
--------------------------------------------------------------------------------
/build_latest_docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright 2025. ThingsBoard
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | set -e # exit on any error
17 |
18 | # Fetch the current branch name and latest commit ID
19 | BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | sed 's/[\/]/-/g')
20 | COMMIT_ID=$(git rev-parse --short HEAD)
21 |
22 | # Combine them to create a version tag
23 | VERSION_TAG="${BRANCH_NAME}-${COMMIT_ID}"
24 |
25 | echo "$(date) Building project with version tag $VERSION_TAG ..."
26 | set -x
27 |
28 | # multi arch
29 | DOCKER_CLI_EXPERIMENTAL=enabled \
30 | docker buildx build . -t tb-gateway:$VERSION_TAG -f docker/Dockerfile --platform=linux/amd64,linux/arm64 -o type=registry
31 |
32 | set +x
33 | echo "$(date) Done."
34 |
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.4'
2 | services:
3 | # ThingsBoard IoT Gateway Service Configuration
4 | tb-gateway:
5 | image: thingsboard/tb-gateway
6 | container_name: tb-gateway
7 | restart: always
8 |
9 | # Ports bindings - required by some connectors
10 | ports:
11 | - "5000:5000" # Comment if you don't use REST connector and change if you use another port
12 | # Uncomment and modify the following ports based on connector usage:
13 | # - "1052:1052" # BACnet connector
14 | # - "5026:5026" # Modbus TCP connector (Modbus Slave)
15 | # - "50000:50000/tcp" # Socket connector with type TCP
16 | # - "50000:50000/udp" # Socket connector with type UDP
17 |
18 | # Necessary mapping for Linux
19 | extra_hosts:
20 | - "host.docker.internal:host-gateway"
21 |
22 | # Environment variables
23 | environment:
24 | - TB_GW_HOST=host.docker.internal
25 | - TB_GW_PORT=1883
26 | - TB_GW_ACCESS_TOKEN=YOUR_ACCESS_TOKEN
27 | - TB_GW_LOGS_PATH=/thingsboard_gateway/logs
28 |
29 | # Volumes bind
30 | volumes:
31 | - tb-gw-config:/thingsboard_gateway/config
32 | - tb-gw-logs:/thingsboard_gateway/logs
33 | - tb-gw-extensions:/thingsboard_gateway/extensions
34 |
35 | # Volumes declaration for configurations, extensions and configuration
36 | volumes:
37 | tb-gw-config:
38 | name: tb-gw-config
39 | tb-gw-logs:
40 | name: tb-gw-logs
41 | tb-gw-extensions:
42 | name: tb-gw-extensions
43 |
--------------------------------------------------------------------------------
/for_build/DEBIAN/preinst:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "Preinst: Ensuring required directories exist..."
5 |
6 | for dir in /etc/thingsboard-gateway /var/lib/thingsboard_gateway /var/log/thingsboard-gateway /var/lib/thingsboard_gateway/extensions; do
7 | if [ ! -d "$dir" ]; then
8 | echo "Preinst: Creating directory $dir..."
9 | mkdir -p "$dir"
10 | else
11 | echo "Preinst: Directory $dir already exists."
12 | fi
13 | done
14 |
15 | echo "Preinst: Checking for system user 'thingsboard_gateway'..."
16 | if id "thingsboard_gateway" >/dev/null 2>&1; then
17 | echo "Preinst: User 'thingsboard_gateway' already exists. Skipping creation."
18 | else
19 | adduser --system --gecos "ThingsBoard-Gateway Service" --disabled-password --group --home /var/lib/thingsboard_gateway thingsboard_gateway
20 | echo "Preinst: Created user 'thingsboard_gateway'."
21 | fi
22 |
23 | exit 0
24 |
--------------------------------------------------------------------------------
/for_build/DEBIAN/pydist-overrides:
--------------------------------------------------------------------------------
1 | pip python3-pip; PEP386
2 | lxml python3-lxml; PEP386
3 | cryptography python3-cryptography; PEP386
4 | opcua python3-opcua; PEP386
5 | paho-mqtt python3-paho-mqtt; PEP386
6 | pymodbus python3-pymodbus; PEP386
7 | pyserial python3-pyserial; PEP386
8 | pyyaml python3-PyYAML; PEP386
9 | pyrsistent python3-pyrsistent; PEP386
10 | importlib python3-importlib; PEP386
11 | jsonparh-rw python3-jsonpath-rw; PEP386
12 | regex python3-regex; PEP386
13 | requests python3-requests; PEP386
14 | pyinquirer python3-pyinquirer; PEP386
--------------------------------------------------------------------------------
/for_build/etc/systemd/system/thingsboard-gateway.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=ThingsBoard Gateway
3 | After=multi-user.target
4 | ConditionPathExists=/etc/thingsboard-gateway/config/tb_gateway.json
5 |
6 | [Service]
7 | Type=simple
8 | User=thingsboard_gateway
9 | Group=thingsboard_gateway
10 |
11 | WorkingDirectory=/var/lib/thingsboard_gateway
12 | ExecStart=/var/lib/thingsboard_gateway/venv/bin/python3 -c "from thingsboard_gateway.tb_gateway import daemon; daemon()"
13 | ExecStop=/bin/kill -INT $MAINPID
14 | ExecReload=/bin/kill -TERM $MAINPID
15 |
16 | Restart=on-failure
17 |
18 | [Install]
19 | WantedBy=multi-user.target
20 |
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/connector.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/connector.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/converter.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/converter.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/database.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/database.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/extension.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/extension.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/service.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/service.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/storage.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/storage.log
--------------------------------------------------------------------------------
/for_build/var/log/thingsboard-gateway/tb_connection.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/for_build/var/log/thingsboard-gateway/tb_connection.log
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 | packaging==23.1
3 | jsonpath-rw
4 | regex
5 | pip
6 | PyYAML
7 | simplejson
8 | orjson
9 | pybase64
10 | urllib3>=2.3.0
11 | requests>=2.32.3
12 | questionary
13 | pyfiglet
14 | python-dateutil
15 | termcolor
16 | grpcio
17 | mmh3
18 | protobuf<=3.20.0
19 | cachetools
20 | tb-paho-mqtt-client>=2.1.2
21 | tb-mqtt-client>=1.13.5
22 | service-identity
23 | psutil
24 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
--------------------------------------------------------------------------------
/tests/base_test.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import signal
3 | from sys import platform, stdout
4 | from unittest import TestCase
5 | from tests.test_utils.gateway_device_util import GatewayDeviceUtil
6 |
7 | logging.basicConfig(level=logging.DEBUG,
8 | format='%(asctime)s - %(levelname)s - %(module)s - %(lineno)d - %(message)s',
9 | datefmt='%Y-%m-%d %H:%M:%S')
10 |
11 | LOG = logging.getLogger("TEST")
12 | LOG.level = logging.DEBUG
13 | stream_handler = logging.StreamHandler(stdout)
14 | LOG.addHandler(stream_handler)
15 | LOG.trace = LOG.debug
16 |
17 |
18 | class BaseTest(TestCase):
19 | TIMEOUT = 600 # 10 minutes in seconds
20 |
21 | def __init__(self, *args, **kwargs):
22 | super().__init__(*args, **kwargs)
23 | self.log = LOG
24 | self.log.trace = self.log.debug
25 |
26 | @classmethod
27 | def setUpClass(cls):
28 | GatewayDeviceUtil.get_gateway_device()
29 |
30 | @classmethod
31 | def tearDownClass(cls):
32 | GatewayDeviceUtil.delete_gateway_device()
33 | assert GatewayDeviceUtil.GATEWAY_DEVICE is None
34 |
35 | def setUp(self):
36 | if platform.startswith("win"):
37 | signal.signal(signal.SIGALRM, self._timeout_handler)
38 | signal.alarm(self.TIMEOUT)
39 |
40 | def tearDown(self):
41 | signal.alarm(0) # Disable the alarm
42 |
43 | def _timeout_handler(self, signum, frame):
44 | raise TimeoutError(f"Test exceeded the time limit of {self.TIMEOUT} seconds")
--------------------------------------------------------------------------------
/tests/blackbox/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/blackbox/__init__.py
--------------------------------------------------------------------------------
/tests/blackbox/connectors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/blackbox/connectors/__init__.py
--------------------------------------------------------------------------------
/tests/blackbox/connectors/modbus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/blackbox/connectors/modbus/__init__.py
--------------------------------------------------------------------------------
/tests/blackbox/connectors/opcua/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/blackbox/connectors/opcua/__init__.py
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/default_modbus_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 1000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [
31 | {
32 | "tag": "string_read",
33 | "type": "string",
34 | "functionCode": 4,
35 | "objectsCount": 2,
36 | "address": 0
37 | }
38 | ],
39 | "timeseries": [],
40 | "attributeUpdates": [],
41 | "rpc": []
42 | }
43 | ]
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/rpc_configs/coils_writing_rpc_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "BIG",
19 | "wordOrder": "BIG",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 2000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 1,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 1,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": [
49 | {
50 | "tag": "bits",
51 | "type": "coils",
52 | "functionCode": 15,
53 | "objectsCount": 16,
54 | "address": 0
55 | }
56 | ]
57 | }
58 | ]
59 | }
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/rpc_configs/coils_writing_rpc_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 2000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 1,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 1,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": [
49 | {
50 | "tag": "bits",
51 | "type": "coils",
52 | "functionCode": 15,
53 | "objectsCount": 16,
54 | "address": 0
55 | }
56 | ]
57 | }
58 | ]
59 | }
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/rpc_configs/discrete_inputs_writing_rpc_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "BIG",
19 | "wordOrder": "BIG",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 2000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 2,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 2,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": [
49 | {
50 | "tag": "bits",
51 | "type": "bits",
52 | "functionCode": 6,
53 | "objectsCount": 16,
54 | "address": 0
55 | }
56 | ]
57 | }
58 | ]
59 | }
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/rpc_configs/discrete_inputs_writing_rpc_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 2000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 2,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 2,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": [
49 | {
50 | "tag": "bits",
51 | "type": "bits",
52 | "functionCode": 6,
53 | "objectsCount": 16,
54 | "address": 0
55 | }
56 | ]
57 | }
58 | ]
59 | }
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/uplink_configs/modbus_uplink_converter_coils_reading_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "BIG",
19 | "wordOrder": "BIG",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 1000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 1,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 1,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": []
49 | }
50 | ]
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/uplink_configs/modbus_uplink_converter_coils_reading_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 1000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 1,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 1,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": []
49 | }
50 | ]
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/uplink_configs/modbus_uplink_converter_discrete_input_reading_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "BIG",
19 | "wordOrder": "BIG",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 1000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 2,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 2,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": []
49 | }
50 | ]
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/configs/uplink_configs/modbus_uplink_converter_discrete_input_reading_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 1000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [],
31 | "timeseries": [
32 | {
33 | "tag": "bits",
34 | "type": "bits",
35 | "functionCode": 2,
36 | "objectsCount": 16,
37 | "address": 0
38 | },
39 | {
40 | "tag": "bit",
41 | "type": "bit",
42 | "functionCode": 2,
43 | "objectsCount": 1,
44 | "address": 0
45 | }
46 | ],
47 | "attributeUpdates": [],
48 | "rpc": []
49 | }
50 | ]
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/modbus_rename_configs/default_modbus_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "Modbus": {
3 | "name": "Modbus",
4 | "type": "modbus",
5 | "logLevel": "DEBUG",
6 | "configuration": "modbus.json",
7 | "configurationJson": {
8 | "name": "Modbus",
9 | "logLevel": "DEBUG",
10 | "master": {
11 | "slaves": [
12 | {
13 | "host": "localhost",
14 | "port": 5021,
15 | "type": "tcp",
16 | "method": "socket",
17 | "timeout": 35,
18 | "byteOrder": "LITTLE",
19 | "wordOrder": "LITTLE",
20 | "retries": true,
21 | "retryOnEmpty": true,
22 | "retryOnInvalid": true,
23 | "pollPeriod": 10000,
24 | "unitId": 2,
25 | "deviceName": "Temp Sensor",
26 | "sendDataOnlyOnChange": false,
27 | "connectAttemptTimeMs": 5000,
28 | "connectAttemptCount": 5,
29 | "waitAfterFailedAttemptsMs": 300000,
30 | "attributes": [
31 | {
32 | "tag": "string_read",
33 | "type": "string",
34 | "functionCode": 4,
35 | "objectsCount": 2,
36 | "address": 0
37 | }
38 | ],
39 | "timeseries": [],
40 | "attributeUpdates": [],
41 | "rpc": []
42 | }
43 | ]
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/discrete_and_coils_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,false,false,false,true,true,true,true,false,true,false,false,true,true]
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/discrete_and_coils_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,false,false,false,true,true,true,true,false,true,false,false,true,true]
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/holding_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": "-30541",
5 | "16uint": "13334",
6 | "16float": "0.0670166015625",
7 | "32int": "-856817645",
8 | "32uint": "2018915246",
9 | "32float": "-0.0000000000000000000000001626903466837544",
10 | "64int": "1243365278113335247",
11 | "64uint": "17275436396653061650",
12 | "64float": "-6065988000872254000000000000000000000000000000000000000000000000000"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/holding_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": "-22137",
5 | "16uint": "4661",
6 | "16float": "13.34375",
7 | "32int": "-4661",
8 | "32uint": "305419897",
9 | "32float": "223547.34375",
10 | "64int": "-3735928550",
11 | "64uint": "1311738468603649775",
12 | "64float": "133.45"
13 | }
14 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/input_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": "-30541",
5 | "16uint": "13334",
6 | "16float": "0.0670166015625",
7 | "32int": "-856817645",
8 | "32uint": "2018915246",
9 | "32float": "-0.0000000000000000000000001626903466837544",
10 | "64int": "1243365278113335247",
11 | "64uint": "17275436396653061650",
12 | "64float": "-6065988000872254000000000000000000000000000000000000000000000000000"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/attrs_update/input_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": "-22137",
5 | "16uint": "4661",
6 | "16float": "13.34375",
7 | "32int": "-4661",
8 | "32uint": "305419897",
9 | "32float": "223547.34375",
10 | "64int": "-3735928550",
11 | "64uint": "1311738468603649775",
12 | "64float": "133.45"
13 | }
14 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/default_slave_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
4 | "16int": "-22136",
5 | "16uint": "4660",
6 | "16float": "12.34375",
7 | "32int": "-4660",
8 | "32uint": "305419896",
9 | "32float": "223546.34375",
10 | "64int": "-3735928559",
11 | "64uint": "1311768468603649775",
12 | "64float": "123.45"
13 | }
14 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/discrete_and_coils_registers_values_reading_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
3 | "bit": true
4 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/discrete_and_coils_registers_values_reading_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
3 | "bit": true
4 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/discrete_and_coils_registers_values_writing_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,false,false,false,true,true,true,true,false,true,false,false,true,true]
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/discrete_and_coils_registers_values_writing_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": [false,true,false,false,false,false,true,true,true,true,false,true,false,false,true,true]
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/holding_registers_values_reading_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
4 | "16int": -30551,
5 | "16uint": 13330,
6 | "16float": 0.067017,
7 | "32int": -856817665,
8 | "32uint": 2018915346,
9 | "32float": 0.0,
10 | "64int": 1243365278113333247,
11 | "64uint": 17275436391653061650,
12 | "64float": -6.0659880008723545e+66
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/holding_registers_values_reading_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
4 | "16int": -22136,
5 | "16uint": 4660,
6 | "16float": 12.34375,
7 | "32int": -4660,
8 | "32uint": 305419896,
9 | "32float": 223546.34375,
10 | "64int": -3735928559,
11 | "64uint": 1311768468603649775,
12 | "64float": 123.45
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/holding_registers_values_writing_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": -30541,
5 | "16uint": 13334,
6 | "16float": 0.067017,
7 | "32int": -856817645,
8 | "32uint": 2018915246,
9 | "32float": -0.020163,
10 | "64int": 1243365278113335247,
11 | "64uint": 17275436396653061650,
12 | "64float": -6065988000872254000000000000000000000000000000000000000000000000000
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/holding_registers_values_writing_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": -22137,
5 | "16uint": 4661,
6 | "16float": 13.34375,
7 | "32int": -4661,
8 | "32uint": 305419897,
9 | "32float": 223547.34375,
10 | "64int": -3735928550,
11 | "64uint": 1311738468603649775,
12 | "64float": 133.45
13 | }
14 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/input_registers_values_reading_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
4 | "4bits": [false,false,true,false],
5 | "16int": -30551,
6 | "16uint": 13330,
7 | "16float": 0.067017,
8 | "32int": -856817665,
9 | "32uint": 2018915346,
10 | "32float": 0.0,
11 | "64int": 1243365278113333247,
12 | "64uint": 17275436391653061650,
13 | "64float": -6.0659880008723545e+66
14 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/input_registers_values_reading_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false],
4 | "4bits": [false,false,true,false],
5 | "16int": -22136,
6 | "16uint": 4660,
7 | "16float": 12.34375,
8 | "32int": -4660,
9 | "32uint": 305419896,
10 | "32float": 223546.34375,
11 | "64int": -3735928559,
12 | "64uint": 1311768468603649775,
13 | "64float": 123.45
14 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/input_registers_values_writing_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "16int": -30541,
5 | "16uint": 13334,
6 | "16float": 0.067017,
7 | "32int": -856817645,
8 | "32uint": 2018915246,
9 | "32float": -0.020163,
10 | "64int": 1243365278113335247,
11 | "64uint": 17275436396653061650,
12 | "64float": -6065988000872254000000000000000000000000000000000000000000000000000
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/rpc/input_registers_values_writing_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcx",
3 | "bits": [false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,true],
4 | "4bits": [false, false, false, false],
5 | "16int": -22137,
6 | "16uint": 4661,
7 | "16float": 13.34375,
8 | "32int": -4661,
9 | "32uint": 305419897,
10 | "32float": 223547.34375,
11 | "64int": -3735928550,
12 | "64uint": 1311738468603649775,
13 | "64float": 133.45
14 | }
15 |
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/discrete_and_coils_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
3 | "bit": "true"
4 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/discrete_and_coils_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
3 | "bit": "true"
4 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/holding_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
4 | "16int": "-30551",
5 | "16uint": "13330",
6 | "16float": "0.067017",
7 | "32int": "-856817665",
8 | "32uint": "2018915346",
9 | "32float": "0.0",
10 | "64int": "1243365278113333247",
11 | "64uint": "17275436391653061650",
12 | "64float": "-6065988000872354500000000000000000000000000000000000000000000000000"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/holding_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
4 | "16int": "-22136",
5 | "16uint": "4660",
6 | "16float": "12.34375",
7 | "32int": "-4660",
8 | "32uint": "305419896",
9 | "32float": "223546.34375",
10 | "64int": "-3735928559",
11 | "64uint": "1311768468603649775",
12 | "64float": "123.45"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/input_registers_values_big.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
4 | "16int": "-30551",
5 | "16uint": "13330",
6 | "16float": "0.067017",
7 | "32int": "-856817665",
8 | "32uint": "2018915346",
9 | "32float": "0.0",
10 | "64int": "1243365278113333247",
11 | "64uint": "17275436391653061650",
12 | "64float": "-6065988000872354500000000000000000000000000000000000000000000000000"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/modbus/test_values/uplink/input_registers_values_little.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "abcd",
3 | "bits": "[false,true,false,true,true,false,true,true,true,true,false,true,false,false,true,false]",
4 | "16int": "-22136",
5 | "16uint": "4660",
6 | "16float": "12.34375",
7 | "32int": "-4660",
8 | "32uint": "305419896",
9 | "32float": "223546.34375",
10 | "64int": "-3735928559",
11 | "64uint": "1311768468603649775",
12 | "64float": "123.45"
13 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/attrs_update_configs/attrs_update_node.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | }
31 | ],
32 | "rpc_methods": [],
33 | "attributes_updates": [
34 | {
35 | "attributeOnThingsBoard": "path",
36 | "attributeOnDevice": "Humidity"
37 | }
38 | ]
39 | }
40 | ]
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/default_opcua_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 5000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [
26 | {
27 | "key": "path",
28 | "path": "${Humidity}"
29 | }
30 | ],
31 | "timeseries": [],
32 | "rpc_methods": [
33 | {
34 | "method": "multiply",
35 | "arguments": [
36 | 2,
37 | 4
38 | ]
39 | }
40 | ],
41 | "attributes_updates": [
42 | {
43 | "attributeOnThingsBoard": "path",
44 | "attributeOnDevice": ".Humidity"
45 | }
46 | ]
47 | }
48 | ]
49 | }
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/rpc_configs/rpc_get_method.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | }
31 | ],
32 | "rpc_methods": [],
33 | "attributes_updates": []
34 | }
35 | ]
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/rpc_configs/rpc_server_method.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | }
31 | ],
32 | "rpc_methods": [
33 | {
34 | "method": "multiply",
35 | "arguments": [2, 4]
36 | }
37 | ],
38 | "attributes_updates": []
39 | }
40 | ]
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/rpc_configs/rpc_set_method.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "i",
29 | "path": "${ns=3;i=2}"
30 | }
31 | ],
32 | "rpc_methods": [],
33 | "attributes_updates": []
34 | }
35 | ]
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/uplink_configs/different_node_finding_methods_config_b.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "${ns=3;b=TestDevice}",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | },
31 | {
32 | "key": "i",
33 | "path": "${ns=3;i=2}"
34 | },
35 | {
36 | "key": "s",
37 | "path": "${ns=3;s=Humidity_S}"
38 | },
39 | {
40 | "key": "g",
41 | "path": "${ns=3;g=018dd02c-fd22-754a-b6d3-5fcae91cd38d}"
42 | },
43 | {
44 | "key": "b",
45 | "path": "${ns=3;b=Status_S}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": []
50 | }
51 | ]
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/uplink_configs/different_node_finding_methods_config_g.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "${ns=5;g=018dd02c-fd22-754a-b6d3-5fcae91cd39d}",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | },
31 | {
32 | "key": "i",
33 | "path": "${ns=5;i=2}"
34 | },
35 | {
36 | "key": "s",
37 | "path": "${ns=5;s=Humidity_S}"
38 | },
39 | {
40 | "key": "g",
41 | "path": "${ns=5;g=018dd02c-fd22-754a-b6d3-5fcae91cd38d}"
42 | },
43 | {
44 | "key": "b",
45 | "path": "${ns=5;b=Status_S}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": []
50 | }
51 | ]
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/uplink_configs/different_node_finding_methods_config_i.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "${ns=3;i=1}",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | },
31 | {
32 | "key": "i",
33 | "path": "${ns=3;i=2}"
34 | },
35 | {
36 | "key": "s",
37 | "path": "${ns=3;s=Humidity_S}"
38 | },
39 | {
40 | "key": "g",
41 | "path": "${ns=3;g=018dd02c-fd22-754a-b6d3-5fcae91cd38d}"
42 | },
43 | {
44 | "key": "b",
45 | "path": "${ns=3;b=Status_S}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": []
50 | }
51 | ]
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/uplink_configs/different_node_finding_methods_config_path.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "Root\\.Objects\\.TempSensor",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | },
31 | {
32 | "key": "i",
33 | "path": "${ns=3;i=2}"
34 | },
35 | {
36 | "key": "s",
37 | "path": "${ns=3;s=Humidity_S}"
38 | },
39 | {
40 | "key": "g",
41 | "path": "${ns=3;g=018dd02c-fd22-754a-b6d3-5fcae91cd38d}"
42 | },
43 | {
44 | "key": "b",
45 | "path": "${ns=3;b=Status_S}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": []
50 | }
51 | ]
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/configs/uplink_configs/different_node_finding_methods_config_s.json:
--------------------------------------------------------------------------------
1 | {
2 | "Opcua": {
3 | "name": "Opcua",
4 | "type": "opcua_asyncio",
5 | "logLevel": "DEBUG",
6 | "configuration": "opcua.json",
7 | "configurationJson": {
8 | "server": {
9 | "name": "OPC-UA Demo Server",
10 | "url": "opc.tcp://127.0.0.1:4840/freeopcua/server/",
11 | "timeoutInMillis": 5000,
12 | "scanPeriodInMillis": 1000,
13 | "disableSubscriptions": true,
14 | "subCheckPeriodInMillis": 100,
15 | "showMap": false,
16 | "security": "Basic128Rsa15",
17 | "identity": {
18 | "type": "anonymous"
19 | },
20 | "mapping": [
21 | {
22 | "deviceNodePattern": "${ns=4;s=TestDevice}",
23 | "deviceNamePattern": "Temp Sensor",
24 | "deviceTypePattern": "default",
25 | "attributes": [],
26 | "timeseries": [
27 | {
28 | "key": "path",
29 | "path": "${Humidity}"
30 | },
31 | {
32 | "key": "i",
33 | "path": "${ns=4;i=2}"
34 | },
35 | {
36 | "key": "s",
37 | "path": "${ns=4;s=Humidity_S}"
38 | },
39 | {
40 | "key": "g",
41 | "path": "${ns=4;g=018dd02c-fd22-754a-b6d3-5fcae91cd38d}"
42 | },
43 | {
44 | "key": "b",
45 | "path": "${ns=4;b=Status_S}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": []
50 | }
51 | ]
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/attrs_update/attrs_update_connection_lost_node.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": "63.2"
3 | }
4 |
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/attrs_update/attrs_update_node_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": 61.2
3 | }
4 |
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/attrs_update/attrs_update_restart_node_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": 61.2
3 | }
4 |
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/default_node_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": "60.5"
3 | }
4 |
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/rpc/rpc_get_method_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "s": "SomeText"
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/rpc/rpc_server_method_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "multiply": 8
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/rpc/rpc_set_method_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": "12"
3 | }
--------------------------------------------------------------------------------
/tests/blackbox/data/opcua/test_values/uplink/different_node_finding_methods_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": "60.5",
3 | "i": "1013.25",
4 | "s": "243.5",
5 | "g": "true",
6 | "b": 12.2
7 | }
8 |
--------------------------------------------------------------------------------
/tests/blackbox/service/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/tests/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.5'
2 | services:
3 | tb:
4 | container_name: tests_tb_1
5 | image: "thingsboard/tb-postgres"
6 | environment:
7 | TB_QUEUE_TYPE: in-memory
8 | volumes:
9 | - tb-data:/data
10 | - tb-logs:/var/log/thingsboard
11 | network_mode: host
12 | gw:
13 | container_name: tests_gw_1
14 | image: "tb-gateway"
15 | environment:
16 | - TB_GW_HOST=127.0.0.1
17 | - TB_GW_PORT=1883
18 | - TB_GW_ACCESS_TOKEN=YOUR_ACCESS_TOKEN
19 | - TB_GW_RATE_LIMITS=0:0
20 | volumes:
21 | - tb-gw-config:/thingsboard_gateway/config
22 | - tb-gw-logs:/thingsboard_gateway/logs
23 | - tb-gw-extensions:/thingsboard_gateway/extensions
24 | network_mode: host
25 | mqtt-broker:
26 | container_name: tests_mqtt_broker_1
27 | image: "thingsboard/tb-gw-mqtt-broker:latest"
28 | network_mode: host
29 | modbus-server:
30 | container_name: tests_modbus_server_1
31 | image: "thingsboard/tb-gw-modbus-server:latest"
32 | network_mode: host
33 | opcua-server:
34 | container_name: tests_opcua_server_1
35 | image: "thingsboard/tb-gw-opcua-server:latest"
36 | network_mode: host
37 | volumes:
38 | tb-data:
39 | name: tb-data
40 | tb-logs:
41 | name: tb-logs
42 | tb-gw-config:
43 | name: tb-gw-config
44 | tb-gw-logs:
45 | name: tb-gw-logs
46 | tb-gw-extensions:
47 | name: tb-gw-extensions
48 |
--------------------------------------------------------------------------------
/tests/integration/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/__init__.py
--------------------------------------------------------------------------------
/tests/integration/connectors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/connectors/__init__.py
--------------------------------------------------------------------------------
/tests/integration/connectors/can/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/connectors/can/__init__.py
--------------------------------------------------------------------------------
/tests/integration/connectors/modbus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/connectors/modbus/__init__.py
--------------------------------------------------------------------------------
/tests/integration/connectors/odbc/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/connectors/odbc/__init__.py
--------------------------------------------------------------------------------
/tests/integration/connectors/opcua/__init__.py:
--------------------------------------------------------------------------------
1 | # TODO Configure environment for these tests
--------------------------------------------------------------------------------
/tests/integration/data/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/data/__init__.py
--------------------------------------------------------------------------------
/tests/integration/data/can/attribute_updates.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": "virtual",
3 | "channel": "virtual_channel",
4 | "backend": {
5 | "fd": true
6 | },
7 | "devices": [
8 | {
9 | "name": "Car",
10 | "strictEval": false,
11 | "attributeUpdates": [
12 | {
13 | "attributeOnThingsBoard": "boolAttr",
14 | "nodeId": 1
15 | },
16 | {
17 | "attribute": "intAttr",
18 | "nodeId": 2,
19 | "isExtendedId": true,
20 | "dataLength": 4,
21 | "dataByteorder": "little"
22 | },
23 | {
24 | "attributeOnThingsBoard": "floatAttr",
25 | "nodeId": 3
26 | },
27 | {
28 | "attribute": "stringAttr",
29 | "nodeId": 4,
30 | "isFd": true,
31 | "dataExpression": "'Test' + value"
32 | },
33 | {
34 | "attributeOnThingsBoard": "wrongConfigAttr",
35 | "nodeId": 123456
36 | }
37 | ]
38 | }
39 | ]
40 | }
--------------------------------------------------------------------------------
/tests/integration/data/can/multiple_polling.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": "virtual",
3 | "channel": "virtual_channel",
4 | "devices": [
5 | {
6 | "name": "TestDevice",
7 | "timeseries": [
8 | {
9 | "key": "testVar1",
10 | "nodeId": 1,
11 | "value": "4:1:int",
12 | "polling": {
13 | "type": "once",
14 | "dataInHex": "01"
15 | }
16 | },
17 | {
18 | "key": "testVar2",
19 | "nodeId": 2,
20 | "value": "4:1:int",
21 | "polling": {
22 | "dataInHex": "02",
23 | "period": 2.5
24 | }
25 | },
26 | {
27 | "key": "testVar3",
28 | "nodeId": 3,
29 | "value": "4:1:int",
30 | "polling": {
31 | "type": "always",
32 | "dataInHex": "03",
33 | "period": 3
34 | }
35 | }
36 | ]
37 | }
38 | ]
39 | }
--------------------------------------------------------------------------------
/tests/integration/data/can/polling_always.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": "virtual",
3 | "channel": "virtual_channel",
4 | "devices": [
5 | {
6 | "name": "TestDevice",
7 | "attributes": [
8 | {
9 | "key": "testVar",
10 | "nodeId": 41,
11 | "value": "4:1:int",
12 | "polling": {
13 | "dataInHex": "CC",
14 | "period": 2
15 | }
16 | }
17 | ]
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/tests/integration/data/can/polling_once.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": "virtual",
3 | "channel": "virtual_channel",
4 | "devices": [
5 | {
6 | "name": "TestDevice",
7 | "attributes": [
8 | {
9 | "key": "testVar",
10 | "nodeId": 12345,
11 | "isExtendedId": true,
12 | "value": "4:1:int",
13 | "polling": {
14 | "type": "once",
15 | "dataInHex": "AB CD AB CD"
16 | }
17 | }
18 | ]
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/tests/integration/data/can/rpc.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": "virtual",
3 | "channel": "virtual_channel",
4 | "backend": {
5 | "fd": true
6 | },
7 | "devices": [
8 | {
9 | "name": "Car1",
10 | "enableUnknownRpc": false,
11 | "serverSideRpc": [
12 | {
13 | "method": "sendSameData",
14 | "nodeId": 4,
15 | "isExtendedId": true,
16 | "isFd": true,
17 | "bitrateSwitch": true,
18 | "dataInHex": "aa bb cc dd ee ff aa bb aa bb cc dd ee ff"
19 | },
20 | {
21 | "method": "setSpeed",
22 | "nodeId": 16,
23 | "dataExpression": "userSpeed if maxAllowedSpeed > userSpeed else maxAllowedSpeed",
24 | "dataByteorder": "little",
25 | "dataLength": 2
26 | }
27 | ]
28 | },
29 | {
30 | "name": "Car2",
31 | "overrideRpcConfig": true,
32 | "serverSideRpc": [
33 | {
34 | "method": "sendSameData",
35 | "nodeId": 4,
36 | "isExtendedId": true,
37 | "isFd": true,
38 | "bitrateSwitch": true,
39 | "dataInHex": "aa bb cc dd ee ff aa bb aa bb cc dd ee ff"
40 | }
41 | ]
42 | },
43 | {
44 | "name": "Car3",
45 | "enableUnknownRpc": true,
46 | "serverSideRpc": [
47 | {
48 | "method": "someMethod",
49 | "nodeId": 4,
50 | "dataInHex": "010203"
51 | }
52 | ]
53 | },
54 | {
55 | "name": "Car4",
56 | "serverSideRpc": [
57 | {
58 | "method": "wrongDataMethod",
59 | "nodeId": 4,
60 | "dataInHex": "123",
61 | "response": true
62 | }
63 | ]
64 | }
65 | ]
66 | }
--------------------------------------------------------------------------------
/tests/integration/data/gateway/gateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "thingsboard": {
3 | "host": "127.0.0.1",
4 | "port": 1883,
5 | "remoteShell": false,
6 | "remoteConfiguration": false,
7 | "statistics": {
8 | "enable": false,
9 | "statsSendPeriodInSeconds": 3600,
10 | "configuration": "statistics.json"
11 | },
12 | "minPackSendDelayMS": 0,
13 | "checkConnectorsConfigurationInSeconds": 60,
14 | "handleDeviceRenaming": true,
15 | "checkingDeviceActivity": {
16 | "checkDeviceInactivity": false,
17 | "inactivityTimeoutSeconds": 120,
18 | "inactivityCheckPeriodSeconds": 10
19 | },
20 | "security": {
21 | "accessToken": "YOUR_ACCESS_TOKEN"
22 | },
23 | "qos": 1
24 | },
25 | "storage": {
26 | "type": "memory",
27 | "read_records_count": 100,
28 | "max_records_count": 100000
29 | },
30 | "connectors": [
31 | {
32 | "name": "MQTT Broker Connector",
33 | "type": "mqtt",
34 | "configuration": "mqtt.json"
35 | }
36 | ]
37 | }
--------------------------------------------------------------------------------
/tests/integration/data/modbus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/data/modbus/__init__.py
--------------------------------------------------------------------------------
/tests/integration/data/odbc/odbc_attributes.json:
--------------------------------------------------------------------------------
1 | {
2 | "connection": {
3 | "str": "DO_NOT_EDIT_THIS_PARAMETER.IT WILL BE OVERRIDDEN BY TESTS."
4 | },
5 | "polling": {
6 | "query": "SELECT key, bool_v, str_v, dbl_v, long_v, device_id, ts FROM attributes WHERE ts > ? ORDER BY ts ASC LIMIT 10",
7 | "period": 1,
8 | "iterator": {
9 | "column": "ts",
10 | "query": "SELECT MIN(ts) - 1 FROM attributes"
11 | }
12 | },
13 | "mapping": {
14 | "device": {
15 | "name": "'ODBC ' + str(device_id)"
16 | },
17 | "attributes": [
18 | {
19 | "nameExpression": "key",
20 | "value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
21 | }
22 | ]
23 | }
24 | }
--------------------------------------------------------------------------------
/tests/integration/data/odbc/odbc_iterator.json:
--------------------------------------------------------------------------------
1 | {
2 | "connection": {
3 | "str": "DO_NOT_EDIT_THIS_PARAMETER.IT WILL BE OVERRIDDEN BY TESTS.",
4 | "reconnectPeriod": 3
5 | },
6 | "polling": {
7 | "query": "SELECT bool_v, str_v, dbl_v, long_v, device_id, ts FROM timeseries WHERE ts > ? ORDER BY ts ASC LIMIT 2",
8 | "period": 5,
9 | "iterator": {
10 | "column": "ts",
11 | "query": "SELECT MIN(ts) - 1 FROM timeseries",
12 | "persistent": true
13 | }
14 | },
15 | "mapping": {
16 | "sendDataOnlyOnChange": true,
17 | "device": {
18 | "name": "'ODBC ' + str(device_id)"
19 | },
20 | "timeseries": [
21 | {
22 | "name": "value",
23 | "value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
24 | }
25 | ]
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/integration/data/odbc/odbc_rpc.json:
--------------------------------------------------------------------------------
1 | {
2 | "connection": {
3 | "str": "DO_NOT_EDIT_THIS_PARAMETER.IT WILL BE OVERRIDDEN BY TESTS.",
4 | "reconnectPeriod": 5
5 | },
6 | "polling": {
7 | "query": "SELECT key FROM attributes WHERE ts > ? ORDER BY ts ASC LIMIT 10",
8 | "iterator": {
9 | "column": "ts",
10 | "query": "SELECT MAX(ts) FROM attributes"
11 | }
12 | },
13 | "mapping": {
14 | "device": {
15 | "name": "'ODBC ' + entity_id"
16 | },
17 | "timeseries": [
18 | {
19 | "name": "value",
20 | "value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
21 | }
22 | ]
23 | },
24 | "serverSideRpc": {
25 | "methods": [
26 | "decrement_value",
27 | {
28 | "name": "increment_value",
29 | "query": "CALL increment_value()"
30 | },
31 | {
32 | "name": "reset_values",
33 | "params": [ "test", 25 ]
34 | },
35 | {
36 | "name": "update_values",
37 | "params": [ "hello world", 150 ],
38 | "query": "CALL update_values(?,?)"
39 | },
40 | "get_values"
41 | ]
42 | }
43 | }
--------------------------------------------------------------------------------
/tests/integration/data/odbc/odbc_timeseries.json:
--------------------------------------------------------------------------------
1 | {
2 | "connection": {
3 | "str": "DO_NOT_EDIT_THIS_PARAMETER.IT WILL BE OVERRIDDEN BY TESTS.",
4 | "attributes": {
5 | "autocommit": false,
6 | "timeout": 0
7 | }
8 | },
9 | "pyodbc": {
10 | "pooling": false,
11 | "native_uuid": true
12 | },
13 | "polling": {
14 | "query": "SELECT bool_v, str_v, dbl_v, long_v, device_id, ts FROM timeseries WHERE ts > ? ORDER BY ts ASC LIMIT 10",
15 | "period": 1,
16 | "iterator": {
17 | "column": "ts",
18 | "query": "SELECT MIN(ts) - 1 FROM timeseries"
19 | }
20 | },
21 | "mapping": {
22 | "device": {
23 | "type": "postgres",
24 | "name": "'ODBC ' + str(device_id)"
25 | },
26 | "timeseries": [
27 | {
28 | "name": "value",
29 | "value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
30 | }
31 | ]
32 | }
33 | }
--------------------------------------------------------------------------------
/tests/integration/data/odbc/sqlite3.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/data/odbc/sqlite3.db
--------------------------------------------------------------------------------
/tests/integration/data/opcua/connection_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "name": "OPC-UA Default Server",
4 | "url": "localhost:4841/freeopcua/server/",
5 | "timeoutInMillis": 5000,
6 | "scanPeriodInMillis": 5000,
7 | "disableSubscriptions":false,
8 | "subCheckPeriodInMillis": 100,
9 | "showMap": false,
10 | "security": "Basic128Rsa15",
11 | "identity": {
12 | "type": "anonymous"
13 | },
14 | "mapping": [
15 | {
16 | "deviceNodePattern": "Root\\.Objects\\.Device1",
17 | "deviceNamePattern": "Device ${Root\\.Objects\\.Device1\\.serialNumber}",
18 | "attributes": [
19 | {
20 | "key": "temperature °C",
21 | "path": "${ns=2;i=5}"
22 | }
23 | ],
24 | "timeseries": [
25 | {
26 | "key": "humidity",
27 | "path": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}"
28 | },
29 | {
30 | "key": "batteryLevel",
31 | "path": "${Battery\\.batteryLevel}"
32 | }
33 | ],
34 | "rpc_methods": [
35 | {
36 | "method": "multiply",
37 | "arguments": [2, 4]
38 | }
39 | ],
40 | "attributes_updates": [
41 | {
42 | "attributeOnThingsBoard": "deviceName",
43 | "attributeOnDevice": "Root\\.Objects\\.Device1\\.serialNumber"
44 | }
45 | ]
46 | }
47 | ]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/integration/data/opcua/opcua_test_connection.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "name": "OPC-UA Default Server",
4 | "url": "localhost:4841",
5 | "timeoutInMillis": 5000,
6 | "scanPeriodInMillis": 5000,
7 | "disableSubscriptions":false,
8 | "subCheckPeriodInMillis": 100,
9 | "showMap": false,
10 | "security": "Basic256Sha256",
11 | "identity": {
12 | "type": "anonymous"
13 | },
14 | "mapping": [
15 | {
16 | "deviceNodePattern": "Root\\.Objects\\.Machine1",
17 | "deviceNamePattern": "Machine 1",
18 | "attributes": [
19 | {
20 | "key": "SerialNumber",
21 | "path": "${SerialNumber}"
22 | }
23 | ],
24 | "timeseries": [
25 | {
26 | "key": "IntState",
27 | "path": "${IntState}"
28 | }
29 | ],
30 | "rpc_methods": [],
31 | "attributes_updates": [ ]
32 | },
33 | {
34 | "deviceNodePattern": "Root\\.Objects\\.Machine2",
35 | "deviceNamePattern": "Machine 2",
36 | "attributes": [
37 | {
38 | "key": "SerialNumber",
39 | "path": "${ns=2;i=5}"
40 | }
41 | ],
42 | "timeseries": [
43 | {
44 | "key": "IntState",
45 | "path": "${ns=2;i=6}"
46 | }
47 | ],
48 | "rpc_methods": [],
49 | "attributes_updates": [ ]
50 | },
51 | {
52 | "deviceNodePattern": "Root\\.Objects\\.Collection",
53 | "deviceNamePattern": "Machine 3",
54 | "attributes": [
55 | {
56 | "key": "SerialNumber",
57 | "path": "${Machine3\\.SerialNumber}"
58 | }
59 | ],
60 | "timeseries": [
61 | {
62 | "key": "IntState",
63 | "path": "${Machine3\\.Int\\State}"
64 | }
65 | ],
66 | "rpc_methods": [],
67 | "attributes_updates": [ ]
68 | }
69 | ]
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/integration/integration_base_test.py:
--------------------------------------------------------------------------------
1 | from tests.base_test import BaseTest
2 |
3 |
4 | class IntegrationBaseTest(BaseTest):
5 |
6 | def setUp(self):
7 | super().setUp()
8 |
9 | def tearDown(self):
10 | super().tearDown()
--------------------------------------------------------------------------------
/tests/integration/service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/integration/service/__init__.py
--------------------------------------------------------------------------------
/tests/requirements.txt:
--------------------------------------------------------------------------------
1 | wheel
2 | twine
3 | packaging==23.1
4 | jsonpath-rw
5 | regex
6 | pip
7 | PyYAML
8 | simplejson
9 | urllib3<=1.26.15
10 | requests>=2.31.0
11 | questionary
12 | pyfiglet
13 | termcolor
14 | grpcio==1.58.0
15 | mmh3
16 | protobuf<=3.20.0
17 | cachetools
18 | tb-paho-mqtt-client>=2.1.2
19 | tb-mqtt-client==1.13.5
20 | service-identity
21 | pyjwt==2.6.0
22 | tb-rest-client
23 | pyopenssl
24 | opcua
25 | asyncua
26 | twisted
27 | pymodbus==3.0.0
28 | pyserial
29 | pyserial-asyncio
30 | python-can
31 | python-dateutil
32 | bacpypes3>=0.0.102
33 | aiohttp
34 | puresnmp>=2.0.0
35 | slixmpp
36 | psutil
37 | orjson
38 | pybase64
39 |
--------------------------------------------------------------------------------
/tests/start_tests.sh:
--------------------------------------------------------------------------------
1 | export PYTHONPATH="${PYTHONPATH}:$(pwd)"
2 | python3 -m venv venv
3 | source venv/bin/activate
4 | pip install -r tests/requirements.txt --no-cache-dir
5 | pip install pyjwt==2.6.0 --no-cache-dir
6 | pip install tb-rest-client --no-cache-dir
7 | cp docker/Dockerfile .
8 | docker build -t tb-gateway --load .
9 | docker compose --file tests/docker-compose.yml up -d
10 | sleep 60
11 | python3 -m unittest discover -s . -p 'test_*.py' -v
12 | docker compose down
13 | deactivate
14 | rm -rf venv
--------------------------------------------------------------------------------
/tests/test_utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/test_utils/__init__.py
--------------------------------------------------------------------------------
/tests/tests.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/tests.py
--------------------------------------------------------------------------------
/tests/unit/BaseUnitTest.py:
--------------------------------------------------------------------------------
1 | from tests.base_test import BaseTest
2 |
3 |
4 | class BaseUnitTest(BaseTest):
5 |
6 | @classmethod
7 | def setUpClass(cls):
8 | pass
9 |
10 | def setUp(self):
11 | super().setUp()
12 |
13 | def tearDown(self):
14 | super().tearDown()
--------------------------------------------------------------------------------
/tests/unit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/__init__.py
--------------------------------------------------------------------------------
/tests/unit/connectors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/connectors/__init__.py
--------------------------------------------------------------------------------
/tests/unit/connectors/bacnet/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/anonym_type/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "parameters": {
3 | "host": "0.0.0.0",
4 | "port": 21,
5 | "TLSSupport": false,
6 | "security": {
7 | "type": "anonymous"
8 | }
9 | },
10 | "paths": [
11 | {
12 | "devicePatternName": "asd",
13 | "devicePatternType": "Device",
14 | "delimiter": ",",
15 | "path": "fol/*_hello*.txt",
16 | "readMode": "FULL",
17 | "maxFileSize": 5,
18 | "pollPeriod": 500,
19 | "txtFileDataView": "SLICED",
20 | "withSortingFiles": true,
21 | "attributes": [
22 | {
23 | "type": "string",
24 | "key": "temp",
25 | "value": "[1:]"
26 | },
27 | {
28 | "type": "string",
29 | "key": "tmp",
30 | "value": "[0:1]"
31 | }
32 | ],
33 | "timeseries": [
34 | {
35 | "type": "integer",
36 | "key": "[0:1]",
37 | "value": "[0:1]"
38 | },
39 | {
40 | "type": "integer",
41 | "key": "temp",
42 | "value": "[1:]"
43 | }
44 | ]
45 | }
46 | ],
47 | "requestsMapping": {
48 | "attributeUpdates": [
49 | {
50 | "path": "fol/hello.json",
51 | "deviceNameFilter": ".*",
52 | "writingMode": "WRITE",
53 | "valueExpression": "{'${attributeKey}':'${attributeValue}'}"
54 | }
55 | ],
56 | "serverSideRpc": [
57 | {
58 | "deviceNameFilter": ".*",
59 | "methodFilter": "read",
60 | "valueExpression": "${params}"
61 | },
62 | {
63 | "deviceNameFilter": ".*",
64 | "methodFilter": "write",
65 | "valueExpression": "${params}"
66 | }
67 | ]
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/anonym_type/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "0.0.0.0",
3 | "port": 21,
4 | "TLSSupport": false,
5 | "security": {
6 | "type": "anonymous"
7 | },
8 | "paths": [
9 | {
10 | "devicePatternName": "asd",
11 | "devicePatternType": "Device",
12 | "delimiter": ",",
13 | "path": "fol/*_hello*.txt",
14 | "readMode": "FULL",
15 | "maxFileSize": 5,
16 | "pollPeriod": 500,
17 | "txtFileDataView": "SLICED",
18 | "withSortingFiles": true,
19 | "attributes": [
20 | {
21 | "key": "temp",
22 | "value": "[1:]"
23 | },
24 | {
25 | "key": "tmp",
26 | "value": "[0:1]"
27 | }
28 | ],
29 | "timeseries": [
30 | {
31 | "type": "int",
32 | "key": "[0:1]",
33 | "value": "[0:1]"
34 | },
35 | {
36 | "type": "int",
37 | "key": "temp",
38 | "value": "[1:]"
39 | }
40 | ]
41 | }
42 | ],
43 | "attributeUpdates": [
44 | {
45 | "path": "fol/hello.json",
46 | "deviceNameFilter": ".*",
47 | "writingMode": "WRITE",
48 | "valueExpression": "{'${attributeKey}':'${attributeValue}'}"
49 | }
50 | ],
51 | "serverSideRpc": [
52 | {
53 | "deviceNameFilter": ".*",
54 | "methodFilter": "read",
55 | "valueExpression": "${params}"
56 | },
57 | {
58 | "deviceNameFilter": ".*",
59 | "methodFilter": "write",
60 | "valueExpression": "${params}"
61 | }
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/attribute_updates/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "parameters": {
3 | "host": "0.0.0.0",
4 | "port": 21,
5 | "TLSSupport": false,
6 | "security": {
7 | "type": "basic",
8 | "username": "admin",
9 | "password": "admin"
10 | }
11 | },
12 | "paths": [
13 | {
14 | "devicePatternName": "asd",
15 | "devicePatternType": "Device",
16 | "delimiter": ",",
17 | "path": "fol/*_hello*.txt",
18 | "readMode": "FULL",
19 | "maxFileSize": 5,
20 | "pollPeriod": 500,
21 | "txtFileDataView": "SLICED",
22 | "withSortingFiles": true,
23 | "attributes": [
24 | {
25 | "type": "string",
26 | "key": "temp",
27 | "value": "[1:]"
28 | },
29 | {
30 | "type": "string",
31 | "key": "tmp",
32 | "value": "[0:1]"
33 | }
34 | ],
35 | "timeseries": [
36 | {
37 | "type": "integer",
38 | "key": "[0:1]",
39 | "value": "[0:1]"
40 | },
41 | {
42 | "type": "integer",
43 | "key": "temp",
44 | "value": "[1:]"
45 | }
46 | ]
47 | }
48 | ],
49 | "requestsMapping": {
50 | "attributeUpdates": [
51 | ],
52 | "serverSideRpc": [
53 | {
54 | "deviceNameFilter": ".*",
55 | "methodFilter": "read",
56 | "valueExpression": "${params}"
57 | },
58 | {
59 | "deviceNameFilter": ".*",
60 | "methodFilter": "write",
61 | "valueExpression": "${params}"
62 | }
63 | ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/attribute_updates/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "0.0.0.0",
3 | "port": 21,
4 | "TLSSupport": false,
5 | "security": {
6 | "type": "basic",
7 | "username": "admin",
8 | "password": "admin"
9 | },
10 | "paths": [
11 | {
12 | "devicePatternName": "asd",
13 | "devicePatternType": "Device",
14 | "delimiter": ",",
15 | "path": "fol/*_hello*.txt",
16 | "readMode": "FULL",
17 | "maxFileSize": 5,
18 | "pollPeriod": 500,
19 | "txtFileDataView": "SLICED",
20 | "withSortingFiles": true,
21 | "attributes": [
22 | {
23 | "key": "temp",
24 | "value": "[1:]"
25 | },
26 | {
27 | "key": "tmp",
28 | "value": "[0:1]"
29 | }
30 | ],
31 | "timeseries": [
32 | {
33 | "type": "int",
34 | "key": "[0:1]",
35 | "value": "[0:1]"
36 | },
37 | {
38 | "type": "int",
39 | "key": "temp",
40 | "value": "[1:]"
41 | }
42 | ]
43 | }
44 | ],
45 | "attributeUpdates": [
46 | ],
47 | "serverSideRpc": [
48 | {
49 | "deviceNameFilter": ".*",
50 | "methodFilter": "read",
51 | "valueExpression": "${params}"
52 | },
53 | {
54 | "deviceNameFilter": ".*",
55 | "methodFilter": "write",
56 | "valueExpression": "${params}"
57 | }
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/basic_type/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "parameters": {
3 | "host": "0.0.0.0",
4 | "port": 21,
5 | "TLSSupport": false,
6 | "security": {
7 | "type": "basic",
8 | "username": "admin",
9 | "password": "admin"
10 | }
11 | },
12 | "paths": [
13 | {
14 | "devicePatternName": "asd",
15 | "devicePatternType": "Device",
16 | "delimiter": ",",
17 | "path": "fol/*_hello*.txt",
18 | "readMode": "FULL",
19 | "maxFileSize": 5,
20 | "pollPeriod": 500,
21 | "txtFileDataView": "SLICED",
22 | "withSortingFiles": true,
23 | "attributes": [
24 | {
25 | "type": "string",
26 | "key": "temp",
27 | "value": "[1:]"
28 | },
29 | {
30 | "type": "string",
31 | "key": "tmp",
32 | "value": "[0:1]"
33 | }
34 | ],
35 | "timeseries": [
36 | {
37 | "type": "integer",
38 | "key": "[0:1]",
39 | "value": "[0:1]"
40 | },
41 | {
42 | "type": "integer",
43 | "key": "temp",
44 | "value": "[1:]"
45 | }
46 | ]
47 | }
48 | ],
49 | "requestsMapping": {
50 | "attributeUpdates": [
51 | {
52 | "path": "fol/hello.json",
53 | "deviceNameFilter": ".*",
54 | "writingMode": "WRITE",
55 | "valueExpression": "{'${attributeKey}':'${attributeValue}'}"
56 | }
57 | ],
58 | "serverSideRpc": [
59 | {
60 | "deviceNameFilter": ".*",
61 | "methodFilter": "read",
62 | "valueExpression": "${params}"
63 | },
64 | {
65 | "deviceNameFilter": ".*",
66 | "methodFilter": "write",
67 | "valueExpression": "${params}"
68 | }
69 | ]
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/unit/connectors/ftp/data/basic_type/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "0.0.0.0",
3 | "port": 21,
4 | "TLSSupport": false,
5 | "security": {
6 | "type": "basic",
7 | "username": "admin",
8 | "password": "admin"
9 | },
10 | "paths": [
11 | {
12 | "devicePatternName": "asd",
13 | "devicePatternType": "Device",
14 | "delimiter": ",",
15 | "path": "fol/*_hello*.txt",
16 | "readMode": "FULL",
17 | "maxFileSize": 5,
18 | "pollPeriod": 500,
19 | "txtFileDataView": "SLICED",
20 | "withSortingFiles": true,
21 | "attributes": [
22 | {
23 | "key": "temp",
24 | "value": "[1:]"
25 | },
26 | {
27 | "key": "tmp",
28 | "value": "[0:1]"
29 | }
30 | ],
31 | "timeseries": [
32 | {
33 | "type": "int",
34 | "key": "[0:1]",
35 | "value": "[0:1]"
36 | },
37 | {
38 | "type": "int",
39 | "key": "temp",
40 | "value": "[1:]"
41 | }
42 | ]
43 | }
44 | ],
45 | "attributeUpdates": [
46 | {
47 | "path": "fol/hello.json",
48 | "deviceNameFilter": ".*",
49 | "writingMode": "WRITE",
50 | "valueExpression": "{'${attributeKey}':'${attributeValue}'}"
51 | }
52 | ],
53 | "serverSideRpc": [
54 | {
55 | "deviceNameFilter": ".*",
56 | "methodFilter": "read",
57 | "valueExpression": "${params}"
58 | },
59 | {
60 | "deviceNameFilter": ".*",
61 | "methodFilter": "write",
62 | "valueExpression": "${params}"
63 | }
64 | ]
65 | }
66 |
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/connectors/mqtt/__init__.py
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/attribute_requests/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "requestsMapping": {
17 | "serverSideRpc": {},
18 | "connectRequests": {},
19 | "disconnectRequests": {},
20 | "attributeRequests": [
21 | {
22 | "retain": false,
23 | "qos": 0,
24 | "topicFilter": "v1/devices/me/attributes/request",
25 | "deviceInfo": {
26 | "deviceNameExpressionSource": "message",
27 | "deviceNameExpression": "${serialNumber}"
28 | },
29 | "attributeNameExpressionSource": "message",
30 | "attributeNameExpression": "${versionAttribute}, ${pduAttribute}",
31 | "topicExpression": "devices/${deviceName}/attrs",
32 | "valueExpression": "${attributeKey}: ${attributeValue}"
33 | }
34 | ],
35 | "attributeUpdates": {}
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/attribute_requests/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "attributeRequests": [
17 | {
18 | "retain": false,
19 | "qos": 0,
20 | "topicFilter": "v1/devices/me/attributes/request",
21 | "deviceNameJsonExpression": "${serialNumber}",
22 | "attributeNameJsonExpression": "${versionAttribute}, ${pduAttribute}",
23 | "topicExpression": "devices/${deviceName}/attrs",
24 | "valueExpression": "${attributeKey}: ${attributeValue}"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/attribute_updates/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "requestsMapping": {
17 | "serverSideRpc": {},
18 | "connectRequests": {},
19 | "disconnectRequests": {},
20 | "attributeRequests": {},
21 | "attributeUpdates": [
22 | {
23 | "retain": true,
24 | "qos": 0,
25 | "deviceNameFilter": ".*",
26 | "attributeFilter": "uploadFrequency",
27 | "topicExpression": "sensor/${deviceName}/${attributeKey}",
28 | "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
29 | }
30 | ]
31 | }
32 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/attribute_updates/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "attributeUpdates": [
17 | {
18 | "retain": true,
19 | "qos": 0,
20 | "deviceNameFilter": ".*",
21 | "attributeFilter": "uploadFrequency",
22 | "topicExpression": "sensor/${deviceName}/${attributeKey}",
23 | "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/connect_requests/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "requestsMapping": {
17 | "serverSideRpc": {},
18 | "connectRequests": [
19 | {
20 | "topicFilter": "sensor/connect",
21 | "deviceInfo": {
22 | "deviceNameExpressionSource": "message",
23 | "deviceNameExpression": "${serialNumber}"
24 | }
25 | },
26 | {
27 | "topicFilter": "sensor/+/connect",
28 | "deviceInfo": {
29 | "deviceNameExpressionSource": "topic",
30 | "deviceNameExpression": "(?<=sensor/)(.*?)(?=/connect)"
31 | }
32 | }
33 | ],
34 | "disconnectRequests": {},
35 | "attributeRequests": {},
36 | "attributeUpdates": {}
37 | }
38 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/connect_requests/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "connectRequests": [
17 | {
18 | "topicFilter": "sensor/connect",
19 | "deviceNameJsonExpression": "${serialNumber}"
20 | },
21 | {
22 | "topicFilter": "sensor/+/connect",
23 | "deviceNameTopicExpression": "(?<=sensor/)(.*?)(?=/connect)"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/disconnect_requests/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "requestsMapping": {
17 | "serverSideRpc": {},
18 | "connectRequests": {},
19 | "disconnectRequests": [
20 | {
21 | "topicFilter":"sensor/disconnect",
22 | "deviceInfo":{
23 | "deviceNameExpressionSource":"message",
24 | "deviceNameExpression":"${serialNumber}"
25 | }
26 | },
27 | {
28 | "topicFilter":"sensor/+/disconnect",
29 | "deviceInfo":{
30 | "deviceNameExpressionSource":"topic",
31 | "deviceNameExpression":"(?<=sensor/)(.*?)(?=/disconnect)"
32 | }
33 | }
34 | ],
35 | "attributeRequests": {},
36 | "attributeUpdates": {}
37 | }
38 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/disconnect_requests/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "disconnectRequests": [
17 | {
18 | "topicFilter": "sensor/disconnect",
19 | "deviceNameJsonExpression": "${serialNumber}"
20 | },
21 | {
22 | "topicFilter": "sensor/+/disconnect",
23 | "deviceNameTopicExpression": "(?<=sensor/)(.*?)(?=/disconnect)"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/server_side_rpc/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "requestsMapping": {
17 | "serverSideRpc": [
18 | {
19 | "deviceNameFilter": ".*",
20 | "methodFilter": "echo",
21 | "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
22 | "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}",
23 | "responseTimeout": 1000,
24 | "valueExpression": "${params}"
25 | },
26 | {
27 | "deviceNameFilter": ".*",
28 | "methodFilter": "no-reply",
29 | "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
30 | "valueExpression": "${params}"
31 | }
32 | ],
33 | "connectRequests": {},
34 | "disconnectRequests": {},
35 | "attributeRequests": {},
36 | "attributeUpdates": {}
37 | }
38 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/mqtt/data/server_side_rpc/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "broker": {
3 | "name": "Default Local Broker",
4 | "host": "127.0.0.1",
5 | "port": 1883,
6 | "clientId": "ThingsBoard_gateway",
7 | "version": 5,
8 | "maxMessageNumberPerWorker": 10,
9 | "maxNumberOfWorkers": 100,
10 | "sendDataOnlyOnChange": false,
11 | "security": {
12 | "type": "anonymous"
13 | }
14 | },
15 | "mapping": [],
16 | "serverSideRpc": [
17 | {
18 | "deviceNameFilter": ".*",
19 | "methodFilter": "echo",
20 | "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
21 | "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}",
22 | "responseTimeout": 1000,
23 | "valueExpression": "${params}"
24 | },
25 | {
26 | "deviceNameFilter": ".*",
27 | "methodFilter": "no-reply",
28 | "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
29 | "valueExpression": "${params}"
30 | }
31 | ]
32 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/opcua/__init__.py:
--------------------------------------------------------------------------------
1 | # TODO Configure environment for these tests
--------------------------------------------------------------------------------
/tests/unit/connectors/socket/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/connectors/socket/__init__.py
--------------------------------------------------------------------------------
/tests/unit/connectors/socket/data/new_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "socket": {
3 | "type": "TCP",
4 | "address": "127.0.0.1",
5 | "port": 50000,
6 | "bufferSize": 1024
7 | },
8 | "devices": [
9 | {
10 | "address": "*:*",
11 | "deviceName": "Device Example",
12 | "deviceType": "default",
13 | "encoding": "utf-8",
14 | "telemetry": [
15 | {
16 | "key": "temp",
17 | "byteFrom": 0,
18 | "byteTo": -1
19 | },
20 | {
21 | "key": "hum",
22 | "byteFrom": 0,
23 | "byteTo": 2
24 | }
25 | ],
26 | "attributes": [
27 | {
28 | "key": "name",
29 | "byteFrom": 0,
30 | "byteTo": -1
31 | },
32 | {
33 | "key": "num",
34 | "byteFrom": 2,
35 | "byteTo": 4
36 | }
37 | ],
38 | "attributeRequests": [
39 | {
40 | "type": "shared",
41 | "requestExpressionSource": "expression",
42 | "attributeNameExpressionSource": "expression",
43 | "requestExpression": "${[0:3]==atr}",
44 | "attributeNameExpression": "[3:]"
45 | }
46 | ],
47 | "attributeUpdates": [
48 | {
49 | "encoding": "utf-16",
50 | "attributeOnThingsBoard": "sharedName"
51 | }
52 | ],
53 | "serverSideRpc": [
54 | {
55 | "methodRPC": "rpcMethod1",
56 | "withResponse": true,
57 | "encoding": "utf-8"
58 | }
59 | ]
60 | }
61 | ]
62 | }
--------------------------------------------------------------------------------
/tests/unit/connectors/socket/data/old_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "TCP",
3 | "address": "127.0.0.1",
4 | "port": 50000,
5 | "bufferSize": 1024,
6 | "devices": [
7 | {
8 | "addressFilter": "*:*",
9 | "deviceName": "Device Example",
10 | "deviceType": "default",
11 | "encoding": "utf-8",
12 | "telemetry": [
13 | {
14 | "key": "temp",
15 | "byteFrom": 0,
16 | "byteTo": -1
17 | },
18 | {
19 | "key": "hum",
20 | "byteFrom": 0,
21 | "byteTo": 2
22 | }
23 | ],
24 | "attributes": [
25 | {
26 | "key": "name",
27 | "byteFrom": 0,
28 | "byteTo": -1
29 | },
30 | {
31 | "key": "num",
32 | "byteFrom": 2,
33 | "byteTo": 4
34 | }
35 | ],
36 | "attributeRequests": [
37 | {
38 | "type": "shared",
39 | "requestExpression": "${[0:3]==atr}",
40 | "attributeNameExpression": "[3:]"
41 | }
42 | ],
43 | "attributeUpdates": [
44 | {
45 | "encoding": "utf-16",
46 | "attributeOnThingsBoard": "sharedName"
47 | }
48 | ],
49 | "serverSideRpc": [
50 | {
51 | "methodRPC": "rpcMethod1",
52 | "withResponse": true,
53 | "encoding": "utf-8"
54 | }
55 | ]
56 | }
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/tests/unit/connectors/socket/test_socket_backward_compatibility_adapter.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from os import path
3 | from tests.unit.BaseUnitTest import BaseUnitTest
4 | from simplejson import load
5 | from thingsboard_gateway.connectors.socket.backward_compatibility_adapter import BackwardCompatibilityAdapter
6 |
7 |
8 | class SocketBackwardCompatibilityAdapterTests(BaseUnitTest):
9 | CONFIG_PATH = path.join(path.dirname(path.dirname(path.dirname(path.abspath(__file__)))),
10 | "connectors" + path.sep + "socket" + path.sep + "data" + path.sep)
11 |
12 | @staticmethod
13 | def convert_json(config_path):
14 | with open(config_path, 'r') as file:
15 | config = load(file)
16 |
17 | return config
18 |
19 | def setUp(self):
20 | self.maxDiff = 8000
21 | self.adapter = BackwardCompatibilityAdapter(config={})
22 |
23 | def test_is_old_config(self):
24 | is_old_config = self.convert_json(self.CONFIG_PATH + 'old_config.json')
25 | self.assertTrue(is_old_config, True)
26 |
27 | def test_convert_with_empty_config(self):
28 | result = self.adapter.convert()
29 | expected_result = {'socket':
30 | {'address': '127.0.0.1',
31 | 'bufferSize': 1024,
32 | 'port': 50000,
33 | 'type': 'TCP'}
34 | }
35 | self.assertEqual(expected_result, result)
36 |
37 | def test_convert_from_old_to_new_config(self):
38 | self.adapter._config = self.convert_json(self.CONFIG_PATH + 'old_config.json')
39 | result = self.adapter.convert()
40 | expected_result = self.convert_json(self.CONFIG_PATH + 'new_config.json')
41 | self.assertEqual(expected_result, result)
42 |
43 |
44 | if __name__ == '__main__':
45 | unittest.main()
46 |
--------------------------------------------------------------------------------
/tests/unit/converters/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
--------------------------------------------------------------------------------
/tests/unit/converters/can/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/converters/can/__init__.py
--------------------------------------------------------------------------------
/tests/unit/converters/modbus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/converters/modbus/__init__.py
--------------------------------------------------------------------------------
/tests/unit/converters/mqtt/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/converters/mqtt/__init__.py
--------------------------------------------------------------------------------
/tests/unit/converters/odbc/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/converters/odbc/__init__.py
--------------------------------------------------------------------------------
/tests/unit/converters/request/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/converters/request/__init__.py
--------------------------------------------------------------------------------
/tests/unit/data/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/data/__init__.py
--------------------------------------------------------------------------------
/tests/unit/service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/tests/unit/service/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/config/custom_serial.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Custom serial connector",
3 | "logLevel": "DEBUG",
4 | "uplinkQueueSize": 100000,
5 | "devices": [
6 | {
7 | "name": "SerialDevice1",
8 | "type": "default",
9 | "port": "/dev/ttysUSB0",
10 | "baudrate": 9600,
11 | "converter": "SerialUplinkConverter",
12 | "downlink_converter": "SerialDownlinkConverter",
13 | "telemetry": [
14 | {
15 | "type": "float",
16 | "key": "humidity",
17 | "untilDelimiter": "\r"
18 | }
19 | ],
20 | "attributes": [
21 | {
22 | "key": "SerialNumber",
23 | "type": "string",
24 | "fromByte": 4,
25 | "toByte": -1
26 | }
27 | ],
28 | "attributeUpdates": [
29 | {
30 | "attributeOnPlatform": "attr1",
31 | "stringToDevice": "value = ${attr1}\n"
32 | }
33 | ],
34 | "serverSideRpc": [
35 | {
36 | "method": "setValue",
37 | "type": "int",
38 | "withResponse": true,
39 | "responseType": "string",
40 | "responseUntilDelimiter": "\r",
41 | "responseTimeoutSec": 5
42 | },
43 | {
44 | "method": "getValue",
45 | "type": "string",
46 | "withResponse": false
47 | }
48 | ]
49 | }
50 | ]
51 | }
--------------------------------------------------------------------------------
/thingsboard_gateway/config/ftp.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "0.0.0.0",
3 | "port": 21,
4 | "TLSSupport": false,
5 | "security": {
6 | "type": "basic",
7 | "username": "admin",
8 | "password": "admin"
9 | },
10 | "paths": [
11 | {
12 | "devicePatternName": "asd",
13 | "devicePatternType": "Device",
14 | "delimiter": ",",
15 | "path": "fol/*_hello*.txt",
16 | "readMode": "FULL",
17 | "maxFileSize": 5,
18 | "pollPeriod": 500,
19 | "txtFileDataView": "SLICED",
20 | "withSortingFiles": true,
21 | "attributes": [
22 | {
23 | "key": "temp",
24 | "value": "[1:]"
25 | },
26 | {
27 | "key": "tmp",
28 | "value": "[0:1]"
29 | }
30 | ],
31 | "timeseries": [
32 | {
33 | "type": "int",
34 | "key": "[0:1]",
35 | "value": "[0:1]"
36 | },
37 | {
38 | "type": "int",
39 | "key": "temp",
40 | "value": "[1:]"
41 | }
42 | ]
43 | }
44 | ],
45 | "attributeUpdates": [
46 | {
47 | "path": "fol/hello.json",
48 | "deviceNameFilter": ".*",
49 | "writingMode": "WRITE",
50 | "valueExpression": "{'${attributeKey}':'${attributeValue}'}"
51 | }
52 | ],
53 | "serverSideRpc": [
54 | {
55 | "deviceNameFilter": ".*",
56 | "methodFilter": "read",
57 | "valueExpression": "${params}"
58 | },
59 | {
60 | "deviceNameFilter": ".*",
61 | "methodFilter": "write",
62 | "valueExpression": "${params}"
63 | }
64 | ]
65 | }
66 |
--------------------------------------------------------------------------------
/thingsboard_gateway/config/knx.json:
--------------------------------------------------------------------------------
1 | {
2 | "logLevel": "INFO",
3 | "client": {
4 | "type": "AUTOMATIC",
5 | "addressFormat": "LONG",
6 | "localIp": "0.0.0.0",
7 | "localPort": 3671,
8 | "gatewayIP": "192.168.1.160",
9 | "gatewayPort": 3671,
10 | "individualAddress": "1.0.10",
11 | "rateLimit": 0,
12 | "autoReconnect": true,
13 | "autoReconnectWait": 3,
14 | "gatewaysScanner": {
15 | "enabled": false,
16 | "scanPeriod": 3,
17 | "stopOnFound": false
18 | }
19 | },
20 | "devices": [
21 | {
22 | "deviceInfo": {
23 | "deviceNameDataType": "string",
24 | "deviceNameExpressionSource": "expression",
25 | "deviceNameExpression": "Device ${1/0/5}",
26 | "deviceProfileDataType": "none",
27 | "deviceProfileExpressionSource": "constant",
28 | "deviceProfileNameExpression": "default"
29 | },
30 | "pollPeriod": 5000,
31 | "attributes": [
32 | {
33 | "type": "temperature",
34 | "key": "temperature",
35 | "groupAddress": "1/0/6"
36 | }
37 | ],
38 | "timeseries": [
39 | {
40 | "type": "humidity",
41 | "key": "humidity",
42 | "groupAddress": "1/0/7"
43 | }
44 | ]
45 | }
46 | ],
47 | "attributeUpdates": [
48 | {
49 | "deviceNameFilter": ".*",
50 | "dataType": "precent_U8",
51 | "groupAddress": "1/0/9",
52 | "key": "brightness"
53 | }
54 | ],
55 | "serverSideRpc": [
56 | {
57 | "requestType": "read",
58 | "deviceNameFilter": ".*",
59 | "method": "get_name",
60 | "dataType": "string",
61 | "groupAddress": "1/0/5"
62 | },
63 | {
64 | "requestType": "write",
65 | "deviceNameFilter": ".*",
66 | "method": "set_name",
67 | "dataType": "string",
68 | "groupAddress": "1/0/5"
69 | }
70 | ]
71 | }
72 |
--------------------------------------------------------------------------------
/thingsboard_gateway/config/list.json:
--------------------------------------------------------------------------------
1 | {
2 | "deny": {
3 | "MQTT Broker Connector": [
4 | "Temperature Device",
5 | "(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)"
6 | ],
7 | "Modbus Connector": [
8 | "My Modbus Device"
9 | ]
10 | },
11 | "allow": {
12 | "MQTT Broker Connector": [
13 | "My Temperature Sensor"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/thingsboard_gateway/config/ocpp.json:
--------------------------------------------------------------------------------
1 | {
2 | "centralSystem": {
3 | "name": "Central System",
4 | "host": "127.0.0.1",
5 | "port": 9000,
6 | "connection": {
7 | "type": "insecure"
8 | },
9 | "security": [
10 | {
11 | "type": "token",
12 | "tokens": [
13 | "Bearer ACCESS_TOKEN"
14 | ]
15 | },
16 | {
17 | "type": "basic",
18 | "credentials": [
19 | {
20 | "username": "admin",
21 | "password": "admin"
22 | }
23 | ]
24 | }
25 | ]
26 | },
27 | "chargePoints": [
28 | {
29 | "idRegexpPattern": "bidon/hello/CP_1",
30 | "deviceNameExpression": "${Vendor} ${Model}",
31 | "deviceTypeExpression": "default",
32 | "attributes": [
33 | {
34 | "messageTypeFilter": "MeterValues,",
35 | "key": "temp1",
36 | "value": "${meter_value[:].sampled_value[:].value}"
37 | },
38 | {
39 | "messageTypeFilter": "MeterValues,",
40 | "key": "vendorId",
41 | "value": "${connector_id}"
42 | }
43 | ],
44 | "timeseries": [
45 | {
46 | "messageTypeFilter": "DataTransfer,",
47 | "key": "temp",
48 | "value": "${data.temp}"
49 | }
50 | ],
51 | "attributeUpdates": [
52 | {
53 | "attributeOnThingsBoard": "shared",
54 | "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
55 | }
56 | ],
57 | "serverSideRpc": [
58 | {
59 | "methodRPC": "rpc1",
60 | "withResponse": true,
61 | "valueExpression": "${params}"
62 | }
63 | ]
64 | }
65 | ]
66 | }
--------------------------------------------------------------------------------
/thingsboard_gateway/config/odbc.json:
--------------------------------------------------------------------------------
1 | {
2 | "connection": {
3 | "str": "Driver={PostgreSQL};Server=localhost;Port=5432;Database=thingsboard;Uid=postgres;Pwd=postgres;",
4 | "attributes": {
5 | "autocommit": true,
6 | "timeout": 0
7 | },
8 | "encoding": "utf-8",
9 | "decoding": {
10 | "char": "utf-8",
11 | "wchar": "utf-8",
12 | "metadata": "utf-16le"
13 | },
14 | "reconnect": true,
15 | "reconnectPeriod": 60
16 | },
17 | "pyodbc": {
18 | "pooling": false
19 | },
20 | "polling": {
21 | "query": "SELECT bool_v, str_v, dbl_v, long_v, entity_id, ts FROM ts_kv WHERE ts > ? ORDER BY ts ASC LIMIT 10",
22 | "period": 10,
23 | "iterator": {
24 | "column": "ts",
25 | "query": "SELECT MIN(ts) - 1 FROM ts_kv",
26 | "persistent": false
27 | }
28 | },
29 | "mapping": {
30 | "device": {
31 | "type": "postgres",
32 | "name": "'ODBC ' + entity_id"
33 | },
34 | "attributes": "*",
35 | "timeseries": [
36 | {
37 | "name": "value",
38 | "value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
39 | }
40 | ]
41 | },
42 | "serverSideRpc": {
43 | "enableUnknownRpc": false,
44 | "overrideRpcConfig": true,
45 | "methods": [
46 | "procedureOne",
47 | {
48 | "name": "procedureTwo",
49 | "args": [
50 | "One",
51 | 2,
52 | 3.0
53 | ]
54 | }
55 | ]
56 | }
57 | }
--------------------------------------------------------------------------------
/thingsboard_gateway/config/socket.json:
--------------------------------------------------------------------------------
1 | {
2 | "socket": {
3 | "address": "127.0.0.1",
4 | "type": "TCP",
5 | "port": 50000,
6 | "bufferSize": 1024
7 | },
8 | "devices": [
9 | {
10 | "address": "*:*",
11 | "addressFilter": "*:*",
12 | "deviceName": "Device Example",
13 | "deviceType": "default",
14 | "encoding": "utf-8",
15 | "telemetry": [
16 | {
17 | "key": "temp",
18 | "byteFrom": 0,
19 | "byteTo": -1
20 | },
21 | {
22 | "key": "hum",
23 | "byteFrom": 0,
24 | "byteTo": 2
25 | }
26 | ],
27 | "attributes": [
28 | {
29 | "key": "name",
30 | "byteFrom": 0,
31 | "byteTo": -1
32 | },
33 | {
34 | "key": "num",
35 | "byteFrom": 2,
36 | "byteTo": 4
37 | }
38 | ],
39 | "attributeRequests": [
40 | {
41 | "type": "shared",
42 | "requestExpression": "${[0:3]==atr}",
43 | "attributeNameExpression": "[3:]"
44 | }
45 | ],
46 | "attributeUpdates": [
47 | {
48 | "encoding": "utf-16",
49 | "attributeOnThingsBoard": "sharedName"
50 | }
51 | ],
52 | "serverSideRpc": [
53 | {
54 | "methodRPC": "rpcMethod1",
55 | "withResponse": true,
56 | "encoding": "utf-8"
57 | }
58 | ]
59 | }
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/thingsboard_gateway/config/statistics/statistics_linux.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "timeout": 100,
4 | "command": ["/bin/sh", "-c", "ps -A -o cpu,%mem | awk '{cpu += $1}END{print cpu}'"],
5 | "attributeOnGateway": "CPU"
6 | },
7 | {
8 | "timeout": 100,
9 | "command": ["/bin/sh", "-c" ,"free -m | grep Swap | awk '{print ($3/$2)*100}'"],
10 | "attributeOnGateway": "Memory"
11 | },
12 | {
13 | "timeout": 100,
14 | "command": ["/bin/sh", "-c", "hostname -I"],
15 | "attributeOnGateway": "IP address"
16 | },
17 | {
18 | "timeout": 100,
19 | "command": ["/bin/sh", "-c", "lsb_release -ds"],
20 | "attributeOnGateway": "OS"
21 | },
22 | {
23 | "timeout": 100,
24 | "command": ["/bin/sh", "-c", "uptime"],
25 | "attributeOnGateway": "Uptime"
26 | },
27 | {
28 | "timeout": 100,
29 | "command": ["/bin/sh", "-c", "lsusb"],
30 | "attributeOnGateway": "USBs"
31 | }
32 | ]
--------------------------------------------------------------------------------
/thingsboard_gateway/config/statistics/statistics_macos.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "timeout": 100,
4 | "command": "ps -A -o cpu,%mem | awk '{cpu += $1}END{print cpu}'",
5 | "attributeOnGateway": "CPU"
6 | },
7 | {
8 | "timeout": 100,
9 | "command": "ps -A -o %cpu,%mem | awk '{mem += $2}END{print mem}'",
10 | "attributeOnGateway": "Memory"
11 | },
12 | {
13 | "timeout": 100,
14 | "command": ["/bin/sh", "-c", "hostname -I"],
15 | "attributeOnGateway": "IP address"
16 | },
17 | {
18 | "timeout": 100,
19 | "command": ["/bin/sh", "-c", "cat /etc/*-release | grep \"PRETTY_NAME\" | sed 's/PRETTY_NAME=//g'"],
20 | "attributeOnGateway": "OS"
21 | },
22 | {
23 | "timeout": 100,
24 | "command": ["/bin/sh", "-c", "uptime"],
25 | "attributeOnGateway": "Uptime"
26 | },
27 | {
28 | "timeout": 100,
29 | "command": ["/bin/sh", "-c", "lsusb"],
30 | "attributeOnGateway": "USBs"
31 | }
32 | ]
--------------------------------------------------------------------------------
/thingsboard_gateway/config/statistics/statistics_windows.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "timeout": 100,
4 | "command": ["wmic", "cpu", "get", "loadpercentage"],
5 | "attributeOnGateway": "CPU"
6 | },
7 | {
8 | "timeout": 100,
9 | "command": ["wmic", "OS", "get", "FreeVirtualMemory", "/Value"],
10 | "attributeOnGateway": "Memory"
11 | },
12 | {
13 | "timeout": 100,
14 | "command": ["ipconfig"],
15 | "attributeOnGateway": "IP address"
16 | },
17 | {
18 | "timeout": 1000,
19 | "command": ["systeminfo | findstr /B /C:\"OS Name\""],
20 | "attributeOnGateway": "OS"
21 | },
22 | {
23 | "timeout": 1000,
24 | "command": ["systeminfo | find \"System Boot Time:\""],
25 | "attributeOnGateway": "Uptime"
26 | },
27 | {
28 | "timeout": 100,
29 | "command": ["wmic", "logicaldisk", "where", "drivetype=2", "get", "deviceid, volumename, description"],
30 | "attributeOnGateway": "USBs"
31 | }
32 | ]
--------------------------------------------------------------------------------
/thingsboard_gateway/config/xmpp.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "jid": "gateway@localhost",
4 | "password": "password",
5 | "host": "localhost",
6 | "port": 5222,
7 | "use_ssl": false,
8 | "disable_starttls": false,
9 | "force_starttls": true,
10 | "timeout": 10000,
11 | "plugins": [
12 | "xep_0030",
13 | "xep_0323",
14 | "xep_0325"
15 | ]
16 | },
17 | "devices": [
18 | {
19 | "jid": "device@localhost/TMP_1101",
20 | "deviceNameExpression": "${serialNumber}",
21 | "deviceTypeExpression": "default",
22 | "attributes": [
23 | {
24 | "key": "temperature",
25 | "value": "${temp}"
26 | }
27 | ],
28 | "timeseries": [
29 | {
30 | "key": "humidity",
31 | "value": "${hum}"
32 | },
33 | {
34 | "key": "combination",
35 | "value": "${temp}:${hum}"
36 | }
37 | ],
38 | "attributeUpdates": [
39 | {
40 | "attributeOnThingsBoard": "shared",
41 | "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
42 | }
43 | ],
44 | "serverSideRpc": [
45 | {
46 | "methodRPC": "rpc1",
47 | "withResponse": true,
48 | "valueExpression": "${params}"
49 | }
50 | ]
51 | }
52 | ]
53 | }
54 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/application_service_access_point.py:
--------------------------------------------------------------------------------
1 | from bacpypes3.appservice import ApplicationServiceAccessPoint as AppServiceAccessPoint, ServiceAccessPoint
2 | from bacpypes3.apdu import (
3 | APCISequence,
4 | APDU,
5 | AbortPDU,
6 | ComplexAckPDU,
7 | ConfirmedRequestPDU,
8 | ErrorPDU,
9 | RejectPDU,
10 | SimpleAckPDU,
11 | UnconfirmedRequestPDU,
12 | )
13 |
14 |
15 | class ApplicationServiceAccessPoint(AppServiceAccessPoint):
16 | async def sap_response(self, apdu: APDU) -> None:
17 | if isinstance(apdu, SimpleAckPDU):
18 | xpdu = apdu
19 |
20 | elif isinstance(
21 | apdu, (UnconfirmedRequestPDU, ConfirmedRequestPDU, ComplexAckPDU, ErrorPDU)
22 | ):
23 | try:
24 | xpdu = APCISequence.decode(apdu)
25 | except Exception:
26 | if isinstance(apdu, UnconfirmedRequestPDU):
27 | return
28 |
29 | if isinstance(apdu, ConfirmedRequestPDU):
30 | return
31 |
32 | xpdu = apdu
33 | elif isinstance(apdu, (RejectPDU, AbortPDU)):
34 | xpdu = apdu
35 | else:
36 | raise RuntimeError(f"invalid APDU (10): {type(apdu)}")
37 |
38 | await ServiceAccessPoint.sap_response(self, xpdu)
39 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/bacnet_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | from abc import abstractmethod
15 |
16 | from thingsboard_gateway.connectors.converter import Converter
17 |
18 |
19 | class AsyncBACnetConverter(Converter):
20 | @abstractmethod
21 | def convert(self, data):
22 | pass
23 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/entities/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/connectors/bacnet/entities/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/entities/routers.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from asyncio import Lock
16 |
17 |
18 | class Routers:
19 | def __init__(self):
20 | self.__lock = Lock()
21 | self.__router_info_cache = {}
22 |
23 | async def add_router_info(self, address, info):
24 | await self.__lock.acquire()
25 | try:
26 | if address not in self.__router_info_cache:
27 | self.__router_info_cache[address] = info
28 | finally:
29 | self.__lock.release()
30 |
31 | async def get_router_info_by_address(self, address):
32 | await self.__lock.acquire()
33 | try:
34 | return self.__router_info_cache.get(address)
35 | finally:
36 | self.__lock.release()
37 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/bacnet/entities/uplink_converter_config.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | class UplinkConverterConfig:
16 | def __init__(self, config, device_info, device_details):
17 | self.__config = config
18 |
19 | self.device_details = device_details
20 | self.device_name = device_info.device_name
21 | self.device_type = device_info.device_type
22 | self.__objects_to_read = self.__get_objects_to_read()
23 | self.report_strategy = self.__config.get('reportStrategy', {})
24 |
25 | def __get_objects_to_read(self):
26 | objects_to_read = []
27 |
28 | for section in ('attributes', 'timeseries'):
29 | section_config = self.__config.get(section, [])
30 |
31 | if section_config != '*':
32 | for item in section_config:
33 | object_to_read = {**item, 'type': section}
34 |
35 | if item['objectType'] == 'device':
36 | object_to_read['objectId'] = self.device_details.object_id
37 |
38 | objects_to_read.append(object_to_read)
39 |
40 | return objects_to_read
41 |
42 | @property
43 | def objects_to_read(self):
44 | return self.__objects_to_read
45 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ble/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ble/ble_uplink_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class BLEUplinkConverter(Converter):
19 |
20 | @abstractmethod
21 | def convert(self, config, data):
22 | pass
23 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ble/error_handler.py:
--------------------------------------------------------------------------------
1 | class ErrorHandler:
2 | def __init__(self, e):
3 | self.e = e
4 |
5 | def is_char_not_found(self):
6 | try:
7 | if "could not be found!" in self.e.args[0]:
8 | return True
9 | except IndexError:
10 | return False
11 |
12 | return False
13 |
14 | def is_operation_not_supported(self):
15 | try:
16 | if 'not permitted' in self.e.args[1] or 'not supported' in self.e.args[1]:
17 | return True
18 | except IndexError:
19 | return False
20 |
21 | return False
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/can/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/can/can_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import ABC, abstractmethod
16 |
17 |
18 | class CanConverter(ABC):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/connector.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from abc import ABC, abstractmethod
16 |
17 |
18 | class Connector(ABC):
19 |
20 | @abstractmethod
21 | def open(self):
22 | pass
23 |
24 | @abstractmethod
25 | def close(self):
26 | pass
27 |
28 | @abstractmethod
29 | def get_id(self):
30 | pass
31 |
32 | @abstractmethod
33 | def get_name(self):
34 | pass
35 |
36 | @abstractmethod
37 | def get_type(self):
38 | pass
39 |
40 | @abstractmethod
41 | def get_config(self):
42 | pass
43 |
44 | @abstractmethod
45 | def is_connected(self):
46 | pass
47 |
48 | @abstractmethod
49 | def is_stopped(self):
50 | pass
51 |
52 | @abstractmethod
53 | def on_attributes_update(self, content):
54 | pass
55 |
56 | @abstractmethod
57 | def server_side_rpc_handler(self, content):
58 | pass
59 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from abc import ABC, abstractmethod
16 | from typing import Union
17 |
18 | from thingsboard_gateway.gateway.entities.converted_data import ConvertedData
19 |
20 |
21 | class Converter(ABC):
22 |
23 | @abstractmethod
24 | def convert(self, config, data) -> Union[dict, ConvertedData]:
25 | pass
26 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ftp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ftp/ftp_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class FTPConverter(Converter):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/knx/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/knx/entities/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/knx/knx_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class KNXConverter(Converter):
19 | @abstractmethod
20 | def convert(self, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/modbus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/connectors/modbus/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/modbus/entities/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/connectors/modbus/entities/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/modbus/entities/bytes_downlink_converter_config.py:
--------------------------------------------------------------------------------
1 | from pymodbus.constants import Endian
2 |
3 |
4 | class BytesDownlinkConverterConfig:
5 | def __init__(self, device_name, byte_order, word_order, repack, objects_count, function_code, lower_type, address):
6 | self.device_name = device_name
7 | self.byte_order = Endian.Big if byte_order.upper() == "BIG" else Endian.Little
8 | self.word_order = Endian.Big if word_order.upper() == "BIG" else Endian.Little
9 | self.repack = repack
10 | self.objects_count = objects_count
11 | self.function_code = function_code
12 | self.lower_type = lower_type.lower()
13 | self.address = address
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/modbus/entities/bytes_uplink_converter_config.py:
--------------------------------------------------------------------------------
1 | from pymodbus.constants import Endian
2 |
3 |
4 | class BytesUplinkConverterConfig:
5 | def __init__(self, **kwargs):
6 | self.report_strategy = kwargs.get('reportStrategy')
7 | self.device_name = kwargs['deviceName']
8 | self.device_type = kwargs.get('deviceType', 'default')
9 | self.byte_order = Endian.Big if kwargs.get('byteOrder', 'LITTLE').upper() == "BIG" else Endian.Little
10 | self.word_order = Endian.Big if kwargs.get('wordOrder', 'LITTLE').upper() == "BIG" else Endian.Little
11 | self.telemetry = kwargs.get('timeseries', [])
12 | self.attributes = kwargs.get('attributes', [])
13 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/modbus/modbus_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class ModbusConverter(Converter):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/mqtt/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/mqtt/mqtt_decorators.py:
--------------------------------------------------------------------------------
1 | from thingsboard_gateway.gateway.statistics.decorators import CollectStatistics
2 |
3 |
4 | class CustomCollectStatistics(CollectStatistics):
5 | def __call__(self, func):
6 | def inner(*args, **kwargs):
7 | try:
8 | _, __, data, ___ = args
9 | self.collect(self.start_stat_type, data)
10 | except ValueError:
11 | pass
12 |
13 | return func(*args, **kwargs)
14 |
15 | return inner
16 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/mqtt/mqtt_uplink_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class MqttUplinkConverter(Converter):
19 |
20 | @abstractmethod
21 | def convert(self, config, data):
22 | pass
23 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ocpp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/ocpp/ocpp_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class OcppConverter(Converter):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/odbc/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/odbc/odbc_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import ABC, abstractmethod
16 |
17 |
18 | class OdbcConverter(ABC):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/opcua/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/connectors/opcua/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/opcua/opcua_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from typing import Union
16 |
17 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
18 | from thingsboard_gateway.gateway.entities.converted_data import ConvertedData
19 |
20 |
21 | class OpcUaConverter(Converter):
22 | @abstractmethod
23 | def convert(self, config, val) -> Union[dict, ConvertedData]:
24 | pass
25 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/request/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/request/request_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class RequestConverter(Converter):
19 | @abstractmethod
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/request/request_uplink_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class RequestUplinkConverter(Converter):
19 |
20 | @abstractmethod
21 | def convert(self, config, data):
22 | pass
23 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/rest/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/rest/rest_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter
16 |
17 |
18 | class RESTConverter(Converter):
19 |
20 | def convert(self, config, data):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/snmp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/snmp/snmp_downlink_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter
16 | from thingsboard_gateway.gateway.statistics.decorators import CollectStatistics
17 |
18 |
19 | class SNMPDownlinkConverter(Converter):
20 | def __init__(self, config):
21 | self.__config = config
22 |
23 | @CollectStatistics(start_stat_type='allReceivedBytesFromTB',
24 | end_stat_type='allBytesSentToDevices')
25 | def convert(self, config, data):
26 | return data["params"]
27 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/socket/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/socket/backward_compatibility_adapter.py:
--------------------------------------------------------------------------------
1 | from copy import deepcopy
2 |
3 |
4 | class BackwardCompatibilityAdapter:
5 | def __init__(self, config):
6 | self._config = deepcopy(config)
7 |
8 | @staticmethod
9 | def is_old_config(config):
10 | return config.get('socket') is None
11 |
12 | def convert(self):
13 | socket_type = self._config.pop('type', 'TCP')
14 | address = self._config.pop('address', '127.0.0.1')
15 | port = self._config.pop('port', 50000)
16 | buffer_size = self._config.pop('bufferSize', 1024)
17 |
18 | self._config['socket'] = {
19 | 'type': socket_type,
20 | 'address': address,
21 | 'port': port,
22 | 'bufferSize': buffer_size
23 | }
24 |
25 | for device in self._config.get('devices', []):
26 | if device.get('addressFilter'):
27 | address_filter = device.pop('addressFilter')
28 | device['address'] = address_filter
29 |
30 | for attribute_requests in device.get('attributeRequests', []):
31 | attribute_requests['requestExpressionSource'] = 'expression'
32 | attribute_requests['attributeNameExpressionSource'] = 'expression'
33 |
34 | return self._config
35 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/socket/socket_decorators.py:
--------------------------------------------------------------------------------
1 | from thingsboard_gateway.gateway.statistics.decorators import CollectStatistics
2 |
3 |
4 | class CustomCollectStatistics(CollectStatistics):
5 | def __call__(self, func):
6 | def inner(*args, **kwargs):
7 | try:
8 | _, __, ___, data = args
9 | self.collect(self.start_stat_type, data)
10 | except ValueError:
11 | pass
12 |
13 | return func(*args, **kwargs)
14 |
15 | return inner
16 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/socket/socket_uplink_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class SocketUplinkConverter(Converter):
19 |
20 | @abstractmethod
21 | def convert(self, config, data):
22 | pass
23 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/xmpp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/xmpp/device.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import List
3 |
4 |
5 | @dataclass
6 | class Device:
7 | jid: str
8 | device_name_expression: str
9 | device_type_expression: str
10 | attributes: List
11 | timeseries: List
12 | attribute_updates: List
13 | server_side_rpc: List
14 | converter = None
15 |
16 | def set_converter(self, converter):
17 | self.converter = converter
18 |
--------------------------------------------------------------------------------
/thingsboard_gateway/connectors/xmpp/xmpp_converter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from thingsboard_gateway.connectors.converter import Converter, abstractmethod
16 |
17 |
18 | class XmppConverter(Converter):
19 | @abstractmethod
20 | def convert(self, config, val):
21 | pass
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/bacnet/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/extensions/bacnet/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/bacnet_old/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/ble/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/can/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/ftp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/extensions/ftp/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/knx/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/modbus/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/modbus_old/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/extensions/modbus_old/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/mqtt/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/ocpp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/odbc/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/opcua/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/request/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/rest/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/serial/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/snmp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/socket/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/extensions/xmpp/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/constant_enums.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from enum import Enum
16 |
17 |
18 | class DeviceActions(Enum):
19 | UNKNOWN = 0,
20 | CONNECT = 1,
21 | DISCONNECT = 2
22 |
23 |
24 | class DownlinkMessageType(Enum):
25 | Response = 0,
26 | ConnectorConfigurationMsg = 1,
27 | GatewayAttributeUpdateNotificationMsg = 2,
28 | GatewayAttributeResponseMsg = 3,
29 | GatewayDeviceRpcRequestMsg = 4,
30 | UnregisterConnectorMsg = 5,
31 | ConnectorGetConnectedDevicesResponseMsg = 6
32 |
33 |
34 | class Status(Enum):
35 | FAILURE = 1,
36 | NOT_FOUND = 2,
37 | SUCCESS = 3,
38 | NO_NEW_DATA = 4
39 | FORBIDDEN_DEVICE = 5
40 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/device_filter.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import simplejson
4 |
5 |
6 | class DeviceFilter:
7 | def __init__(self, config_path):
8 | self._config_path = config_path
9 | self._config = self._load_config()
10 |
11 | def _load_config(self):
12 | if self._config_path:
13 | with open(self._config_path, 'r') as file:
14 | return simplejson.load(file)
15 |
16 | return {'deny': {}, 'allow': {}}
17 |
18 | def validate_device(self, connector_name, data):
19 | for con_name, device_list in self._config['deny'].items():
20 | if con_name == connector_name:
21 | for device in device_list:
22 | if re.fullmatch(device, data['deviceName']):
23 | return False
24 |
25 | for con_name, device_list in self._config['allow'].items():
26 | if con_name == connector_name:
27 | for device in device_list:
28 | if re.fullmatch(device, data['deviceName']):
29 | return True
30 |
31 | return True
32 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/entities/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/gateway/entities/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/entities/attributes.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from typing import Dict, Any, Union
16 |
17 | from thingsboard_gateway.gateway.entities.datapoint_key import DatapointKey
18 |
19 |
20 | class Attributes:
21 | def __init__(self, values: Dict[DatapointKey, Any] = None):
22 | self.values: Dict[DatapointKey, Any] = values or {}
23 |
24 | def __str__(self):
25 | return f"Attributes(values={self.values})"
26 |
27 | def __hash__(self):
28 | return hash(tuple(self.values.items()))
29 |
30 | def to_dict(self) -> Dict[str, Any]:
31 | return {key.key if isinstance(key, DatapointKey) else key: value for key, value in self.values.items()}
32 |
33 | def __getitem__(self, item: DatapointKey) -> Any:
34 | return self.values[item]
35 |
36 | def __iter__(self):
37 | return iter(self.values)
38 |
39 | def __setitem__(self, key: DatapointKey, value):
40 | self.values[key] = value
41 |
42 | def __len__(self):
43 | return len(self.values)
44 |
45 | def update(self, attributes: Union[Dict[DatapointKey, Any], 'Attributes']):
46 | self.values.update(attributes if isinstance(attributes, dict) else attributes.values)
47 |
48 | def items(self):
49 | return self.values.items()
50 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/entities/datapoint_key.py:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------------------------
2 | # Copyright 2025. ThingsBoard
3 | # #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | # #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | # #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # ------------------------------------------------------------------------------
17 |
18 | from thingsboard_gateway.gateway.entities.report_strategy_config import ReportStrategyConfig
19 |
20 |
21 | class DatapointKey:
22 | def __init__(self, key, report_strategy: ReportStrategyConfig = None):
23 | self.key = key
24 | self.report_strategy = report_strategy
25 |
26 | def __str__(self):
27 | return f"DatapointKey(key={self.key}, report_strategy={self.report_strategy})"
28 |
29 | def __repr__(self):
30 | return self.__str__()
31 |
32 | def __hash__(self):
33 | return hash((self.key, self.report_strategy))
34 |
35 | def __eq__(self, other):
36 | if isinstance(other, DatapointKey):
37 | return self.key == other.key and self.report_strategy == other.report_strategy
38 | return False
39 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/entities/device_event_pack.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/gateway/entities/device_event_pack.py
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/grpc_service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/gateway/grpc_service/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/proto/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Use the following command to generate python code from proto file;
16 |
17 | #$ python3 -m grpc_tools.protoc -Ithingsboard_gateway/gateway/proto --python_out=thingsboard_gateway/gateway/proto/ --grpc_python_out=thingsboard_gateway/gateway/proto/ thingsboard_gateway/gateway/proto/messages.proto
18 |
19 | # Update file messages_pb2_grpc.py:
20 |
21 | # Replace:
22 | # import messages_pb2 as messages__pb2
23 | # With:
24 | # import thingsboard_gateway.gateway.proto.messages_pb2 as messages__pb2
25 |
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/report_strategy/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/gateway/report_strategy/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/shell/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/gateway/shell/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/gateway/statistics/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | # #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | # #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/grpc_connectors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/grpc_connectors/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/grpc_connectors/modbus/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/grpc_connectors/mqtt/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/grpc_connectors/opcua/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/grpc_connectors/socket/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/grpc_connectors/socket/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/event_storage.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from abc import ABC, abstractmethod
16 |
17 |
18 | class EventStorage(ABC):
19 |
20 | def __init__(self, config, logger, main_stop_event):
21 | self._config = config
22 | self._main_stop_event = main_stop_event
23 |
24 | @abstractmethod
25 | def put(self, event):
26 | pass
27 |
28 | @abstractmethod
29 | def get_event_pack(self):
30 | # Returns events from pack
31 | pass
32 |
33 | @abstractmethod
34 | def event_pack_processing_done(self):
35 | # Indicates that events from previous "get_event_pack" may be cleared
36 | pass
37 |
38 | @abstractmethod
39 | def stop(self):
40 | # Stop the storage processing
41 | pass
42 |
43 | @abstractmethod
44 | def len(self):
45 | pass
46 |
47 | @abstractmethod
48 | def update_logger(self):
49 | pass
50 |
51 | def get_configuration(self):
52 | return self._config
53 |
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/file/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/storage/file/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/file/event_storage_files.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from threading import RLock
16 | from typing import Dict
17 |
18 |
19 | class EventStorageFiles:
20 | def __init__(self, state_file, data_files: Dict[str, bool]):
21 | self.state_file = state_file
22 | self.data_files = data_files
23 | self.__data_files_lock = RLock()
24 |
25 | def get_state_file(self):
26 | return self.state_file
27 |
28 | def get_data_files(self):
29 | with self.__data_files_lock:
30 | return sorted(self.data_files.keys())
31 |
32 | def add_data_file(self, data_file):
33 | with self.__data_files_lock:
34 | self.data_files[data_file] = False
35 |
36 | def remove_data_file(self, data_file):
37 | with self.__data_files_lock:
38 | del self.data_files[data_file]
39 |
40 | def confirm_file_processed(self, data_file):
41 | with self.__data_files_lock:
42 | self.data_files[data_file] = True
43 |
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/file/event_storage_reader_pointer.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class EventStorageReaderPointer:
17 | def __init__(self, file, line):
18 | self.file = file
19 | self.line = line
20 |
21 | def __eq__(self, other):
22 | return self.file == other.file and self.line == other.line
23 |
24 | def __hash__(self):
25 | return hash((self.file, self.line))
26 |
27 | def get_file(self):
28 | return self.file
29 |
30 | def get_line(self):
31 | return self.line
32 |
33 | def set_file(self, file):
34 | self.file = file
35 |
36 | def set_line(self, line):
37 | self.line = line
38 |
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/file/file_event_storage_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class FileEventStorageSettings:
17 | def __init__(self, config):
18 | self.data_folder_path = config.get("data_folder_path", "./")
19 | self.max_files_count = config.get("max_file_count", 5)
20 | self.max_records_per_file = config.get("max_records_per_file", 3)
21 | self.max_records_between_fsync = config.get("max_records_between_fsync", 1)
22 | self.max_read_records_count = config.get("max_read_records_count", 1000)
23 |
24 | def get_data_folder_path(self):
25 | return self.data_folder_path
26 |
27 | def get_max_files_count(self):
28 | return self.max_files_count
29 |
30 | def get_max_records_per_file(self):
31 | return self.max_records_per_file
32 |
33 | def get_max_records_between_fsync(self):
34 | return self.max_records_between_fsync
35 |
36 | def get_max_read_records_count(self):
37 | return self.max_read_records_count
38 |
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/memory/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/storage/memory/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/sqlite/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/thingsboard-gateway/af960236f66ee9dadc13c43532168abc90adb40c/thingsboard_gateway/storage/sqlite/__init__.py
--------------------------------------------------------------------------------
/thingsboard_gateway/storage/sqlite/storage_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | class StorageSettings:
16 | def __init__(self, config):
17 | self.data_folder_path = config.get("data_file_path", "./")
18 | self.messages_ttl_check_in_hours = config.get('messages_ttl_check_in_hours', 1) * 3600
19 | self.messages_ttl_in_days = config.get('messages_ttl_in_days', 7)
20 | self.max_read_records_count = config.get('max_read_records_count', 1000)
21 | self.batch_size = config.get('writing_batch_size', 1000)
22 |
--------------------------------------------------------------------------------
/thingsboard_gateway/tb_utility/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/thingsboard_gateway/version.py:
--------------------------------------------------------------------------------
1 | # Copyright 2025. ThingsBoard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | VERSION = "3.7.4"
16 |
--------------------------------------------------------------------------------