Indoor Air Quality (IAQ) sensor modbus connection not working



  • Hello,
    I'm trying to connect an RW-TH version of the Unipi indoor air quality sensor (IAQ) to an Axon S105 via modbus on RS-485 (port 3).
    After modifying /etc/evok.conf and adding /etc/hw_definitions/testIAQ.yaml the web interface does not show the system parameters and I can't poll any IAQ parameters via json or rest API.

    /etc/evok.conf:

    #!!! Do not use '#' for comments !!!
    
    [MAIN]                                          ; !!! ALL MAIN SECTION OPTIONS ARE MANDATORY !!!
    config_version = 2.5                            ; Configuration file version, DO NOT CHANGE!
    use_schema_verification = False                 ; Enabling this will deny any requests that do not match the JSON Schema; NOTE THAT THIS RESULTS IN A SIGNIFICANT INCREASE IN LATENCY AND SHOULD NOT BE USED EXCEPT FOR TESTING
    log_level = DEBUG                               ; Minimum severity of messages to be logged; one of INFO, DEBUG, WARNING, ERROR, CRITICAL
    log_file = /var/log/evok.log                    ; Log file to use; will be cleared on boot
    port = 8080                                     ; !!! Internal API port - only change if you are certain you know what you are doing; FOR OUR WEB INTERFACE THE PORT SHOULD BE CHANGED IN "/etc/evok-nginx.conf" INSTEAD !!!
    webhook_enabled = False                         ; Enables webhook notification - see e.g. https://sendgrid.com/blog/whats-webhook/
    webhook_address = http://127.0.0.1:80           ; Put your server endpoint address here (e.g. http://123.123.123.123:/wh )
    webhook_device_mask = ["input","wd"]            ; List of device types to notify on (written as a JSON list) - adding AI will generate a large amount of messages!
    webhook_complex_events = False                  ; EVOK will send POST requests with the same data as WebSocket, rather than an empty GET request
    soap_server_enabled = False                     ; Enables the simple SOAP server; use only if you need the functionality
    soap_server_port = 8081                         ; !!! IF SOAP SERVER IS ENABLED, THIS PORT NEEDS TO BE UNIQUE (i.e. different from the port setting above) !!!
    force_immediate_state_changes = False           ; Outputs will return the value they are set to, rather than the value that the device is currently aware of
    websocket_all_filtered = False                  ; 'All' WebSocket requests will be subject to the filtering set by 'filter'
    
    [NEURON_1]
    global_id = 1                                   ; Mandatory, REQUIRED TO BE UNIQUE
    allow_register_access = False                   ; Optional, False default
    scan_frequency = 10                             ; Optional, 10 default, scanning frequency in [Hz]
    scan_enabled = True                             ; Optional, True default
    
    ; Below you can find examples for connecting devices over UART; first example is a Neuron extension while the second is a custom third-party device
    ; Devices sharing a port use the port settings of the first device on that port (baud rate, parity, stop bits)
    ; !!! Note that device_name has to match a filename in the /etc/hw_definitions directory !!! See /etc/hw_definitions/CUSTOM_MODBUS_DEVICE.yaml for an example
    
    [EXTENSION_1]
    global_id = 2                                   ; Mandatory, REQUIRED TO BE UNIQUE
    device_name = testIAQ                           ; Mandatory, must match name of .yaml modbus map file in /etc/hw_definitions
    modbus_uart_port = /dev/ttyS1                   ; Mandatory
    neuron_uart_circuit = 1_01                      ; Optional, allows associating extensions with specific Neuron UART-over-Modbus ports (not possible for non-Modbus UART ports, e.g. /dev/ttyUSB0 or /dev/ttyS0)
    allow_register_access = True                    ; Optional, False default, is mandatory with third-party devices
    address = 1                                     ; Optional, 1 default
    scan_frequency = 10                             ; Optional, 10 default, scanning frequency in [Hz]
    scan_enabled = True                             ; Optional, True default
    ; Note that the following settings will be inherited by other devices sharing the same port, i.e. /dev/extcomm/0/0
    baud_rate = 19200                               ; Optional, NEEDS UNIPI IMAGE TO WORK WITH UNIPI SERIAL PORTS! USE API TO CONFIGURE UART MANUALLY IF USING STANDARD RASPBIAN
    parity = N                                      ; Optional, NEEDS UNIPI IMAGE TO WORK WITH UNIPI SERIAL PORTS! USE API TO CONFIGURE UART MANUALLY IF USING STANDARD RASPBIAN
    stop_bits = 1                                   ; Optional, NEEDS UNIPI IMAGE TO WORK WITH UNIPI SERIAL PORTS! USE API TO CONFIGURE UART MANUALLY IF USING STANDARD RASPBIAN
    
    ;[EXTENSION_2]
    ;global_id = 3                                  ; Mandatory, REQUIRED TO BE UNIQUE
    ;device_name = CUSTOM MODBUS DEVICE             ; Mandatory, must match name of .yaml modbus map file in /etc/hw_definitions
    ;modbus_uart_port = /dev/extcomm/0/0            ; Mandatory
    ;neuron_uart_circuit = 1_01                     ; Optional, allows associating extensions with specific Neuron UART-over-Modbus ports (not possible for non-Modbus UART ports, e.g. /dev/ttyUSB0 or /dev/ttyS0)
    ;allow_register_access = True                   ; Mandatory with third-party devices
    ;address = 1                                    ; Optional, 15 default
    ;scan_frequency = 2                             ; Optional, 1 default, scanning frequency in [Hz]
    ;scan_enabled = True                            ; Optional, True default
    
    [OWBUS_1]
    owbus = /dev/i2c-0                              ; Mandatory, scanned bus (--i2c=/dev/i2c-1:ALL or localhost:2122 or 'u' for USB dongle)
    interval = 3                                    ; Mandatory, [s] length of sensor reading
    scan_interval = 300                             ; Mandatory, [s] How often the scanning is done
    
    ; See below for 1Wire extension module configuration
    ; Example for the 1W-4R/4DI extension module, 1W-8R is almost the same, only with inputs instead of relays
    ;
    ; - Map a new 1Wire sensor with the appropriate address, type and interval
    ; - The syntax can be either SENSOR or 1WDEVICE
    ; - Setting the correct reading interval is crucial to achieve ideal performance; the default interval is 15s
    ;
    ;[1WDEVICE_2]
    ;bus = 1
    ;address = 29F39A17000000BC
    ;type = DS2408
    ;interval = 1
    ;
    ;[1WRELAY_10]
    ;sensor = 2
    ;pin = 0
    ;
    ;[1WRELAY_11]
    ;sensor = 2
    ;pin = 1
    ;
    ;[1WRELAY_12]
    ;sensor = 2
    ;pin = 2
    ;
    ;[1WRELAY_13]
    ;sensor = 2
    ;pin = 3
    ;
    ;[1WINPUT_20]
    ;sensor = 2
    ;pin = 4
    ;
    ;[1WINPUT_21]
    ;sensor = 2
    ;pin = 5
    ;
    ;[1WINPUT_22]
    ;sensor = 2
    ;pin = 6
    ;
    ;[1WINPUT_23]
    ;sensor = 2
    ;pin = 7
    
    

    /etc/hw_definitions/testIAQ.yaml:

    # unipi iaq1926 - Indoor air quality sensor
    # File version: 1.0
    # Min. firmware version: 3.00
    ---
    type: testIAQ
    modbus_register_blocks:
        - board_index : 1
          start_reg   : 0
          count       : 86
          frequency   : 50
          type        : input
    
    modbus_features:
        - type        : UNIT_REGISTER
          name        : "temperature"
          count       : 1
          major_group : 1
          value_reg   : 0
          unit        : "  C"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "rel_humid"
          count       : 1
          major_group : 1
          value_reg   : 6
          unit        : "%"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "dew_point"
          count       : 1
          major_group : 1
          value_reg   : 8
          unit        : "  C"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "abs_humid"
          count       : 1
          major_group : 1
          value_reg   : 10
          unit        : "%"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "CO2"
          count       : 1
          major_group : 1
          value_reg   : 18
          unit        : "ppm"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "VOC_index"
          count       : 1
          major_group : 1
          value_reg   : 26
          unit        : "N/A"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "VOC_precision"
          count       : 1
          major_group : 1
          value_reg   : 28
          unit        : "N/A"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "VOC_CO2_eq"
          count       : 1
          major_group : 1
          value_reg   : 34
          unit        : "ppm"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "ambient_light"
          count       : 1
          major_group : 1
          value_reg   : 42
          unit        : "lux"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "atm_pressure"
          count       : 1
          major_group : 1
          value_reg   : 76
          unit        : "hPa"
          datatype    : float32
    
        - type        : UNIT_REGISTER
          name        : "uptime"
          count       : 1
          major_group : 1
          value_reg   : 84
          unit        : "sec"
          datatype    : float32
    
    

    Config web page before enabling modbus extension:
    modbus disabled.JPG
    Config web page after enabling modbus extension:
    modbus enabled testIAQ.JPG

    The Axon is polling the IAQ sensor periodically as expected, and the sensor responds. The waveforms look good on the oscilloscope.
    When polling the sensor manually from command line with mbpoll, the received data looks good:

    root@S105-sn715:/home/unipi# mbpoll -1 -a 1 -b 19200 -t 3 -r 0 -c 86 -P none /dev/ttyS1 -0
    mbpoll 1.4-12 - FieldTalk(tm) Modbus(R) Master Simulator
    Copyright © 2015-2019 Pascal JEAN, https://github.com/epsilonrt/mbpoll
    This program comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type 'mbpoll -w' for details.
    
    Protocol configuration: Modbus RTU
    Slave configuration...: address = [1]
                            start reference = 0, count = 86
    Communication.........: /dev/ttyS1,      19200-8N1
                            t/o 1.00 s, poll rate 1000 ms
    Data type.............: 16-bit register, input register table
    
    -- Polling slave 1...
    [0]:    16824
    [1]:    59049 (-6487)
    [2]:    32704
    [3]:    0
    [4]:    32704
    [5]:    0
    [6]:    16913
    [7]:    53026 (-12510)
    [8]:    16620
    [9]:    53073 (-12463)
    [10]:   16624
    [11]:   48977 (-16559)
    [12]:   32704
    [13]:   0
    [14]:   32704
    [15]:   0
    [16]:   32704
    [17]:   0
    [18]:   32704
    [19]:   0
    [20]:   32704
    [21]:   0
    [22]:   32704
    [23]:   0
    [24]:   32704
    [25]:   0
    [26]:   16864
    [27]:   30269
    [28]:   16256
    [29]:   0
    [30]:   32704
    [31]:   0
    [32]:   32704
    [33]:   0
    [34]:   17404
    [35]:   44002 (-21534)
    [36]:   32704
    [37]:   0
    [38]:   32704
    [39]:   0
    [40]:   32704
    [41]:   0
    [42]:   16757
    [43]:   9542
    [44]:   32704
    [45]:   0
    [46]:   32704
    [47]:   0
    [48]:   32704
    [49]:   0
    [50]:   32704
    [51]:   0
    [52]:   32704
    [53]:   0
    [54]:   32704
    [55]:   0
    [56]:   32704
    [57]:   0
    [58]:   32704
    [59]:   0
    [60]:   32704
    [61]:   0
    [62]:   32704
    [63]:   0
    [64]:   32704
    [65]:   0
    [66]:   32704
    [67]:   0
    [68]:   32704
    [69]:   0
    [70]:   32704
    [71]:   0
    [72]:   32704
    [73]:   0
    [74]:   32704
    [75]:   0
    [76]:   17532
    [77]:   61276 (-4260)
    [78]:   32704
    [79]:   0
    [80]:   32704
    [81]:   0
    [82]:   32704
    [83]:   0
    [84]:   17590
    [85]:   40960 (-24576)
    

    The /var/log/evok.log does not contain any useful information despite the fact that the log level was set to DEBUG:

    2020-09-18 16:09:19,489 - evok - INFO - Starting using config file /etc/evok.conf
    2020-09-18 16:09:19,554 - evok - INFO - YAML Definition loaded: xG18.yaml, type: 3, definition count 0
    2020-09-18 16:09:19,624 - evok - INFO - YAML Definition loaded: xS10.yaml, type: 3, definition count 1
    2020-09-18 16:09:19,708 - evok - INFO - YAML Definition loaded: xS50.yaml, type: 3, definition count 2
    2020-09-18 16:09:19,777 - evok - INFO - YAML Definition loaded: xS40.yaml, type: 3, definition count 3
    2020-09-18 16:09:19,879 - evok - INFO - YAML Definition loaded: /etc/hw_definitions/BuiltIn/S105.yaml, type: UniPiBuiltIn
    2020-09-18 16:09:19,944 - evok - INFO - YAML Definition loaded: xS11.yaml, type: 3, definition count 4
    2020-09-18 16:09:19,974 - evok - INFO - YAML Definition loaded: CUSTOM_MODBUS_DEVICE.yaml, type: 3, definition count 5
    2020-09-18 16:09:20,041 - evok - INFO - YAML Definition loaded: xS30.yaml, type: 3, definition count 6
    2020-09-18 16:09:20,125 - evok - INFO - YAML Definition loaded: xS51.yaml, type: 3, definition count 7
    2020-09-18 16:09:20,215 - evok - INFO - YAML Definition loaded: testIAQ.yaml, type: 3, definition count 8
    2020-09-18 16:09:20,226 - evok - INFO - YAML Definition loaded: evok-alias.yaml, type: 2, definition count 0
    2020-09-18 16:09:20,264 - evok - INFO - HTTP server listening on port: 8080
    2020-09-18 16:09:20,311 - evok - INFO - SPI client started
    2020-09-18 16:09:20,317 - evok - INFO - Entering OWW loop with PID 739
    2020-09-18 16:09:20,318 - evok - INFO - Reading the UART board on Modbus address 1
    2020-09-18 16:09:20,325 - evok - INFO - Reading SPI boards
    2020-09-18 16:09:20,344 - evok - INFO - No board on SPI 2
    2020-09-18 16:09:20,350 - evok - INFO - No board on SPI 3
    2020-09-18 16:09:20,351 - evok - INFO - Alias loaded: <neuron.Relay object at 0xffff81ed5210> al_lights_kitchen
    2020-09-18 16:09:20,353 - evok - INFO - Alias loaded: <neuron.Relay object at 0xffff81ed5390> al_lights_bedroom
    2020-09-18 16:09:20,461 - evok - INFO - Alias loaded: <neuron.Relay object at 0xffff81ed5210> al_lights_kitchen
    2020-09-18 16:09:20,464 - evok - INFO - Alias loaded: <neuron.Relay object at 0xffff81ed5390> al_lights_bedroom
    2020-09-18 16:09:30,402 - evok - DEBUG - New WebSocket client connected
    2020-09-18 16:10:00,860 - evok - DEBUG - New WebSocket client connected
    

    There seems to be a problem with the parsing of the incoming modbus data.
    I would really appreciate some ideas on how to get this to work.
    Thank you!


  • administrators

    Hello @Balardo,

    can you please share reply to the /rest/all GET request?
    e.g. type http://<IP OF YOUR UNIT>/rest/all to your browser.



  • Hello @martin_triska,

    There is the result of the /rest/all request:

    [{"counter_modes": ["Enabled", "Disabled"], "glob_dev_id": 1, "modes": ["Simple", "DirectSwitch"], "value": 0, "circuit": "1_01", "debounce": 50, "counter": 0, "counter_mode": "Enabled", "dev": "input", "mode": "Simple"}, {"counter_modes": ["Enabled", "Disabled"], "glob_dev_id": 1, "modes": ["Simple", "DirectSwitch"], "value": 0, "circuit": "1_02", "debounce": 50, "counter": 0, "counter_mode": "Enabled", "dev": "input", "mode": "Simple"}, {"counter_modes": ["Enabled", "Disabled"], "glob_dev_id": 1, "modes": ["Simple", "DirectSwitch"], "value": 0, "circuit": "1_03", "debounce": 50, "counter": 0, "counter_mode": "Enabled", "dev": "input", "mode": "Simple"}, {"counter_modes": ["Enabled", "Disabled"], "glob_dev_id": 1, "modes": ["Simple", "DirectSwitch"], "value": 0, "circuit": "1_04", "debounce": 50, "counter": 0, "counter_mode": "Enabled", "dev": "input", "mode": "Simple"}, {"relay_type": "digital", "glob_dev_id": 1, "pwm_duty": 0, "dev": "relay", "modes": ["Simple", "PWM"], "pwm_freq": 39, "value": 0, "alias": "al_lights_kitchen", "mode": "Simple", "circuit": "1_01", "pending": false}, {"relay_type": "digital", "glob_dev_id": 1, "pwm_duty": 0, "dev": "relay", "modes": ["Simple", "PWM"], "pwm_freq": 39, "value": 0, "alias": "al_lights_bedroom", "mode": "Simple", "circuit": "1_02", "pending": false}, {"pwm_duty": 0, "glob_dev_id": 1, "pwm_freq": 39, "modes": ["Simple", "PWM"], "value": 0, "circuit": "1_03", "pending": false, "relay_type": "digital", "dev": "relay", "mode": "Simple"}, {"pwm_duty": 0, "glob_dev_id": 1, "pwm_freq": 39, "modes": ["Simple", "PWM"], "value": 0, "circuit": "1_04", "pending": false, "relay_type": "digital", "dev": "relay", "mode": "Simple"}, {"glob_dev_id": 1, "unit": "V", "range_modes": ["10.0"], "value": 0.012965346525057231, "circuit": "1_01", "modes": ["Voltage", "Current"], "range": "10.0", "dev": "ai", "mode": "Voltage"}, {"modes": ["Voltage", "Current", "Resistance"], "value": 0.0, "glob_dev_id": 1, "dev": "ao", "circuit": "1_01", "unit": "V", "mode": "Voltage"}, {"value": 0, "circuit": "1_01", "dev": "led", "glob_dev_id": 1}, {"value": 0, "circuit": "1_02", "dev": "led", "glob_dev_id": 1}, {"value": 0, "circuit": "1_03", "dev": "led", "glob_dev_id": 1}, {"value": 0, "circuit": "1_04", "dev": "led", "glob_dev_id": 1}, {"circuit": "1_01", "value": 0, "glob_dev_id": 1, "dev": "wd", "timeout": 5000, "was_wd_reset": 0, "nv_save": 0}, {"glob_dev_id": 1, "last_comm": 0.03806304931640625, "ver2": "0.2", "sn": 715, "circuit": "1", "model": "S105", "dev": "neuron", "board_count": 1}, {"uart_circuit": "1_01", "dev": "extension", "glob_dev_id": 2, "last_comm": 4.979914903640747, "circuit": "UART_1_2", "model": "testIAQ", "uart_port": "/dev/ttyS1"}, {"conf_value": 3262, "glob_dev_id": 1, "sw_address": 0, "parity_modes": ["None", "Odd", "Even"], "stopb_modes": ["One", "Two"], "speed_modes": ["2400bps", "4800bps", "9600bps", "19200bps", "38400bps", "57600bps", "115200bps"], "dev": "uart", "circuit": "1_01", "parity_mode": "None", "stopb_mode": "One", "speed_mode": "19200bps"}, {"bus": "/dev/i2c-0", "interval": 3.0, "dev": "owbus", "scan_interval": 300.0, "circuit": "1", "do_scan": false, "do_reset": false}, {"name": "dew_point", "value": 12.253130912780762, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_8", "unit": "\u00b0C"}, {"name": "CO2", "value": NaN, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_18", "unit": "ppm"}, {"name": "rel_humid", "value": 57.526512145996094, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_6", "unit": "%"}, {"name": "temperature", "value": 20.957672119140625, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_0", "unit": "\u00b0C"}, {"name": "abs_humid", "value": 10.488215446472168, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_10", "unit": "%"}, {"name": "VOC_CO2_eq", "value": 490.800048828125, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_34", "unit": "ppm"}, {"name": "VOC_index", "value": 19.734819412231445, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_26", "unit": "N/A"}, {"name": "uptime", "value": 1274.0, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_84", "unit": "sec"}, {"name": "ambient_light", "value": 22.00320053100586, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_42", "unit": "lux"}, {"name": "atm_pressure", "value": 999.4600219726562, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_76", "unit": "hPa"}, {"name": "VOC_precision", "value": 1.0, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_1_2_28", "unit": "N/A"}]
    

    It looks like the IAQ sensor is being read, the data looks good.
    Interestingly /rest/all works, but /json/all returns {"status": "error", "message": "Internal Server Error", "code": 500}
    What could be the problem with the json request?
    On what address could we read the sensor? (ex: /res/testIAQ/temperature)
    Thank you for you help.


  • administrators

    Hello @Balardo,

    you are right - there was a bug in schema validation for /json/all endpoint. It should be fixed in the next release.

    According to the direct Modbus unit register access - you can use e.g.
    http://<your IP>/json/unit_register/UART_15_2_42

    to get the ambient_light register:

    {"status": "success", "data": {"name": "ambient_light", "value": 122.51519775390625, "glob_dev_id": 2, "dev": "unit_register", "circuit": "UART_15_2_42", "unit": "lux"}}
    

    Register values has been also added to the web control panel:

    01638744-d5ad-43e4-bc7f-e98cca7e5678-image.png

    You can test it by install the test version:

    sudo su
    apt update && apt install evok=2.3.3.test.20200923165635*
    

Log in to reply