diff --git a/analog_io_modules/infrasensing_env-thum/README.md b/analog_io_modules/infrasensing_env-thum/README.md index 2c3c7914..db775f50 100644 --- a/analog_io_modules/infrasensing_env-thum/README.md +++ b/analog_io_modules/infrasensing_env-thum/README.md @@ -9,10 +9,11 @@ This [Enapter Device Blueprint](https://go.enapter.com/marketplace-readme) integ - Create [Enapter Virtual UCM](https://go.enapter.com/handbook-vucm). - [Upload](https://go.enapter.com/developers-upload-blueprint) this blueprint to Enapter Virtual UCM. - Use the `Configure` command in the Enapter mobile or Web app to set up the device communication parameters: - - IP address (use either static IP or DHCP reservation); - - Modbus Unit ID + - IP address (default - `192.168.11.160`) + - Modbus Unit ID (default - `1`) ## References - [Temperature & Humidity Sensor product page](https://go.enapter.com/infrasensing-env-thum) +- [Infrasensing SensorGateway: How it works video](https://go.enapter.com/infrasensing-sensorgateway-video) - [Modbus TCP manual](https://go.enapter.com/infrasensing-modbus-manual) diff --git a/analog_io_modules/infrasensing_env-thum/firmware.lua b/analog_io_modules/infrasensing_env-thum/firmware.lua index fa6d5b6a..a1d4e38a 100644 --- a/analog_io_modules/infrasensing_env-thum/firmware.lua +++ b/analog_io_modules/infrasensing_env-thum/firmware.lua @@ -6,28 +6,19 @@ MODEL = 'ENV-THUM' -- Configuration variables must be also defined -- in `write_configuration` command arguments in manifest.yml IP_ADDRESS_CONFIG = 'ip_address' +MODBUS_PORT_CONFIG = 'modbus_port' UNIT_ID_CONFIG = 'modbus_unit_id' -- Initiate device firmware. Called at the end of the file. function main() - scheduler.add(30000, send_properties) - scheduler.add(1000, send_telemetry) - config.init({ - [IP_ADDRESS_CONFIG] = { type = 'string', required = true }, - [UNIT_ID_CONFIG] = { type = 'number', required = true }, + [IP_ADDRESS_CONFIG] = { type = 'string', required = true, default = '192.168.11.160' }, + [UNIT_ID_CONFIG] = { type = 'number', required = true, default = 1 }, + [MODBUS_PORT_CONFIG] = { type = 'number', required = true, default = 502 }, }) - enapter.register_command_handler('set_threshold', command_set_threshold) -end - -function send_properties() - local properties = {} - - properties.vendor = VENDOR - properties.model = MODEL - - enapter.send_properties(properties) + scheduler.add(1000, send_telemetry) + scheduler.add(30000, send_properties) end function send_telemetry() @@ -45,44 +36,19 @@ function send_telemetry() local alerts = {} local status = 'ok' - for i = 0, 2 do - local data = device:read_inputs(30200 + i * 32, 2) + for i = 0, 3 do + local data = device:read_inputs(200 + i * 32, 2) if data then telemetry['value' .. i] = toFloat32(data) + else + status = 'no_data' end - local data = device:read_input_status(10201 + i * 32, 1) - if data then - telemetry['alarm_down' .. i] = data[1] - table.insert(alerts, 'alarm_down' .. i) - status = 'down' - end - - local data = device:read_input_status(10202 + i * 32, 1) - if data then - telemetry['alarm_warn' .. i] = data[1] - table.insert(alerts, 'alarm_warn' .. i) - status = 'warning' - end - - local data = device:read_holdings(40200 + i * 32, 2) - if data then - telemetry['thr_high_down' .. i] = toFloat32(data) - end - - local data = device:read_holdings(40202 + i * 32, 2) - if data then - telemetry['thr_high_warn' .. i] = toFloat32(data) - end - - local data = device:read_holdings(40204 + i * 32, 2) - if data then - telemetry['thr_low_high' .. i] = toFloat32(data) - end - - local data = device:read_holdings(40206 + i * 32, 2) + local data = device:read_inputs(201 + i * 32, 1) if data then - telemetry['thr_low_warn' .. i] = toFloat32(data) + telemetry['type' .. i] = get_type(data[1]) + else + status = 'no_data' end end @@ -91,6 +57,58 @@ function send_telemetry() enapter.send_telemetry(telemetry) end +function send_properties() + local properties = {} + + properties.vendor = VENDOR + properties.model = MODEL + + enapter.send_properties(properties) +end + +function get_type(val) + local types = { + [1] = 'Temperature', + [2] = 'Humidity', + [3] = 'Airflow', + [4] = 'Shock', + [5] = 'Dust', + [7] = 'Sound Pressure', + [8] = 'Power Failure Sensor', + [9] = 'Leak', + [10] = 'CO', + [11] = 'Air Pressure', + [12] = 'Security', + [13] = 'Dewpoint', + [14] = 'Fuel Level (Fuel Level Sensor)', + [15] = 'Flow Rate (Fuel Level Sensor)', + [16] = 'Resistance', + [17] = 'TVOC', + [18] = 'CO2', + [19] = 'Motion (EXP4HUB)', + [20] = 'O2', + [21] = 'Light', + [22] = 'CO', + [23] = 'HF', + [24] = 'Volt (AC/DC Power Sensor)', + [25] = 'Amp (AC/DC Power Sensor)', + [26] = 'Watt (AC/DC Power Sensor)', + [27] = 'Watthour (AC/DC Power Sensor)', + [28] = 'Ping', + [29] = 'H2', + [30] = 'Voltage Status', + [31] = 'THD', + [32] = 'Frequency', + [33] = 'Location and Distance', + [34] = 'Tilt (Inclination)', + [35] = 'Particle(PM)', + [36] = 'Radon', + [37] = 'kW (AC Meter3 Power)', + [38] = 'kWh (AC Meter 3 energy)', + } + return types[val] +end + -- Holds global device connection local device @@ -104,46 +122,26 @@ function connect_device() enapter.log('cannot read config: ' .. tostring(err), 'error') return nil, 'cannot_read_config' else - local address, unit_id = values[IP_ADDRESS_CONFIG], values[UNIT_ID_CONFIG] - if not address or not unit_id then + local address, unit_id, port = values[IP_ADDRESS_CONFIG], values[UNIT_ID_CONFIG], values[MODBUS_PORT_CONFIG] + if not address or not unit_id or not port then return nil, 'not_configured' else -- Declare global variable to reuse connection between function calls - device = SensorGwModbusTcp.new(address, tonumber(unit_id)) + device = SensorGwModbusTcp.new(address .. ':' .. port, tonumber(unit_id)) device:connect() return device, nil end end end -function command_set_threshold(ctx, args) - local thresholds = { - ['High Down'] = 0, - ['High Warn'] = 2, - ['Low Down'] = 4, - ['Low Warn'] = 6, - } - - if device then - local err = device:write_holdings(args.node * 32 + 40200 + thresholds[args.threshold], args.value) - if err == 0 then - return 'Reset command is sent' - else - ctx.error('Command failed, Modbus TCP error: ' .. tostring(err)) - end - else - ctx.error('Device connection is not configured') - end -end - function toFloat32(data) local raw_str = string.pack('BBBB', data[1] >> 8, data[1] & 0xff, data[2] >> 8, data[2] & 0xff) return string.unpack('>f', raw_str) end -------------------------------------------- --- InfraSensing SensorGateway ModbusTCP API -------------------------------------------- +----------------------------------------------- +-- InfraSensing SensorGateway Modbus TCP API -- +----------------------------------------------- SensorGwModbusTcp = {} @@ -167,7 +165,7 @@ function SensorGwModbusTcp:read_inputs(address, number) local registers, err = self.modbus:read_inputs(self.unit_id, address, number, 1000) if err and err ~= 0 then - enapter.log('Register ' .. tostring(address) .. ' read error: ' .. err, 'error') + enapter.log('Read input register ' .. tostring(address) .. ' read error: ' .. err, 'error') if err == 1 then -- Sometimes timeout happens and it may break underlying Modbus client, -- this is a temporary workaround which manually reconnects. @@ -185,7 +183,7 @@ function SensorGwModbusTcp:read_input_status(address, number) local registers, err = self.modbus:read_discrete_inputs(self.unit_id, address, number, 1000) if err and err ~= 0 then - enapter.log('Register ' .. tostring(address) .. ' read error: ' .. err, 'error') + enapter.log('Read input status register ' .. tostring(address) .. ' read error: ' .. err, 'error') if err == 1 then -- Sometimes timeout happens and it may break underlying Modbus client, -- this is a temporary workaround which manually reconnects. @@ -203,7 +201,7 @@ function SensorGwModbusTcp:read_holdings(address, number) local registers, err = self.modbus:read_inputs(self.unit_id, address, number, 1000) if err and err ~= 0 then - enapter.log('Register ' .. tostring(address) .. ' read error: ' .. err, 'error') + enapter.log('Read holding register ' .. tostring(address) .. ' read error: ' .. err, 'error') if err == 1 then -- Sometimes timeout happens and it may break underlying Modbus client, -- this is a temporary workaround which manually reconnects. @@ -221,7 +219,7 @@ function SensorGwModbusTcp:write_holdings(address, number) local err = self.modbus:write_holding(self.unit_id, address, number, 1000) if err ~= 0 then - enapter.log('Register ' .. tostring(address) .. ' write error: ' .. err, 'error') + enapter.log('Writ holding register ' .. tostring(address) .. ' write error: ' .. err, 'error') if err == 1 then -- Sometimes timeout happens and it may break underlying Modbus client, -- this is a temporary workaround which manually reconnects. diff --git a/analog_io_modules/infrasensing_env-thum/manifest.yml b/analog_io_modules/infrasensing_env-thum/manifest.yml index f4b68fc1..39f08f17 100644 --- a/analog_io_modules/infrasensing_env-thum/manifest.yml +++ b/analog_io_modules/infrasensing_env-thum/manifest.yml @@ -33,76 +33,58 @@ telemetry: type: string enum: - ok - - warning - - down + - no_data + type0: + display_name: Type Node 0 + type: string + enum: + - Temperature + - Humidity + - Dewpoint + type1: + display_name: Type Node 1 + type: string + enum: + - Temperature + - Humidity + - Dewpoint + type2: + display_name: Type Node 2 + type: string + enum: + - Temperature + - Humidity + - Dewpoint + type3: + display_name: Type Node 3 + type: string + enum: + - Temperature + - Humidity + - Dewpoint + type4: + display_name: Type Node 4 + type: string + enum: + - Temperature + - Humidity + - Dewpoint value0: display_name: SensorGateway Temperature type: float unit: celsius - value1: + value2: display_name: Temperature type: float unit: celsius - value2: + value3: display_name: Humidity type: float unit: percent - alarm_down0: - display_name: SensorGateway Alarm Down - type: integer - alarm_warn0: - display_name: SensorGateway Alarm Warning - type: integer - thr_high_down0: - display_name: SensorGateway Threshold High Down - type: float - thr_high_warn0: - display_name: SensorGateway Threshold High Warn - type: float - thr_low_down0: - display_name: SensorGateway Threshold Low Down - type: float - thr_low_warn0: - display_name: SensorGateway Threshold Low Down - type: float - - alarm_down1: - display_name: Temprerature Sensor Alarm Down - type: integer - alarm_warn1: - display_name: Temperature Sensor Alarm Warning - type: integer - thr_high_down1: - display_name: Temperature Sensor Threshold High Down - type: float - thr_high_warn1: - display_name: Temperature Sensor Threshold High Warn - type: float - thr_low_down1: - display_name: Temperature Sensor Threshold Low Down - type: float - thr_low_warn1: - display_name: Temperature Sensor Threshold Low Down - type: float - - alarm_down2: - display_name: Humidity Sensor Alarm Down - type: integer - alarm_warn2: - display_name: Humidity Sensor Alarm Warning - type: integer - thr_high_down2: - display_name: Humidity Sensor Threshold High Down - type: float - thr_high_warn2: - display_name: Humidity Sensor Threshold High Warn - type: float - thr_low_down2: - display_name: Humidity Sensor Threshold Low Down - type: float - thr_low_warn2: - display_name: Humidity Sensor Threshold Low Down + value4: + display_name: Dew Point type: float + unit: celsius alerts: cannot_read_config: @@ -113,34 +95,8 @@ alerts: severity: info display_name: Modbus TCP Connection Not Configured description: Use "Configure" command to setup Modbus TCP connection. - alarm_warn0: - severity: warning - display_name: SensorGateway Alarm Warning - description: SensorGateway Warning Threshold has been passed. - alarm_down0: - severity: error - display_name: SensorGateway Alarm Down - description: SensorGateway Down Threshold has been passed. - alarm_warn1: - severity: warning - display_name: Temperature Sensor Alarm Warning - description: Temperature Sensor Warning Threshold has been passed. - alarm_down1: - severity: error - display_name: Temperature Sensor Alarm Down - description: Temperature Sensor Down Threshold has been passed. - alarm_warn2: - severity: warning - display_name: Humidity Sensor Alarm Warning - description: Humidity Sensor Warning Threshold has been passed. - alarm_down2: - severity: error - display_name: Humidity Sensor Alarm Down - description: Humidity Sensor Down Threshold has been passed. command_groups: - thresholds: - display_name: Alarm Thresholds connection: display_name: Connection commands: @@ -162,47 +118,28 @@ commands: description: Modbus Unit ID of SensorGateway type: integer required: true + modbus_port: + display_name: Modbus Port + description: Modbus port of SensorGateway + type: integer + required: true read_configuration: display_name: Read Configuration group: connection ui: icon: wrench-outline mobile_quick_access: true - set_threshold: - display_name: Set Alarm Threshold - group: thresholds - ui: - icon: counter - arguments: - node: - display_name: Sensor - description: Number of node. - type: integer - min: 0 - max: 40 - threshold: - display_name: Threshold type - type: string - required: true - enum: - - High Down - - High Warn - - Low Down - - Low Warn - value: - display_name: Threshold value - description: Numeric value of corresponding threshold. - type: float - required: true .cloud: category: analog_io_modules - mobile_main_chart: value1 + mobile_main_chart: value2 mobile_telemetry: - value0 - - value1 - value2 + - value3 + - value4 mobile_charts: - value0 - - value1 - value2 + - value3 + - value4