Multifunctional smart home controller Atom on ESP32

Hello!

I wanted to write about the Atom controllers from i3 Engineering. Its are fully operational with the esphome platform. They have their own software, but have made the esp32 version for engineers who want to keep everything in their hands. In essence, these are controllers that have an interesting set of peripherals on board, capable of automating most wired devices in the house. interesting is their solution with a modular system of loads (i.e. you can change the type of load without an additional controller, thus collecting everything you need in one device).

On board there is a built-in display, which starts up perfectly under the esphome. There are also 4 buttons that can be used to activate modes or manually control devices (not yet started).

The whole periphery was managed to get:

  • 12 input for dry contacts, or digital devices (1-wire also),
  • 8 replaceable modules and 2 relays (others of their models have up to 30 relay outputs, or are immediately adapted for AC / DC dimming). I wrote to the manufacturer, they use the same i2c extenders, so they also have to work out of the box
  • The built-in SSD1306 display works great
  • Support WS2811 / 2812
  • All status indicators on the activity of inputs

The device has hlw8032 installed, but I have not been able to check it yet.

The set includes a usb cable, through which you can flash the controller without disassembling it.

I don’t know how stable wifi is, because I don’t see any external antenna or connector.

The case is made of nonflammable abs, has fastening on din. As far as I understand they have different devices from 3 to 9 modules, which has a different set of peripherals.

Controlled via Home Assistant and ESPHome, everything was working stably

Cool, where is more info about the hw and purchase options?

Info about HW and purchase is on the website of manufacturer https://i3engineering.com/be
They developed controllers with CPU STM32 with their software, and on its basis even began to produce controllers with ESP32 and STM32, which can be programmed independently. ESP32 controllers can be used with ESPHome, Tasmota and the similar. Home assistant is very easy to manage.

Look how you can change the purpose of the outputs here. Control the 220V AC lamp, replace the relay module with a MOSFET module and connect the LED strip to the same output. Magic. )))

1 Like

So cool! But so expensive compared to esp32 with 8 board relay…

199 euro… :thinking::sleepy:

Very nice to see a commercial company advertising support for ha, esphome and tasmota.

Yes - it is much more expensive. But there should be a different approach for each kind of task. The ESP32 + relay is a prototyping kit. Great on the table, ideal for checking the operation of algorithms.

I am an integrator. I need a complete solution in order to put on the building, configure and never return back. Why did I take it for a test? I want to use such controllers in my work/solutions because of the capabilities and characteristics stated by the manufacturer, the most important of them for me are:

  • Reliable, tested relays (there is a model with a starting current of 400A)
  • Relay with a huge in-rush (120A) (Chinese relays 10A stuck after the first switching on a 100W LED lamp with a impulse-based power supply)
  • spring connectors (wago) for connecting sensors, and screw detachable connectors - for loads (this is reliable and reduces installation time)
  • Input and output status leds, output type indicators - for quick diagnostics of problems or during connection
  • OLED display for any purposes you like
  • control buttons on the case for display control or user defined functions.
  • protection on all inputs (overvoltage), there is a possibility of connection of an input signal through an optocoupler to avoid burnout of the controller on long wires
  • current sensors (Hall sensors) on all outputs - to measure consumption and control whether the load is on - just trying to “bring it up” in esphome
  • Ability to add an energy meter unit (hlw8032) to the controller for accurate consumption measurement (up to 10A) for whole house monitoring.
  • Wide supply voltage range, with polarity protection
  • Tested device with manufacturer’s warranty
  • Ability to assemble your controller with additional features
  • In the event of a breakdown, you can only replace the faulty board, not the entire device, and most likely you will not need to reconfigure the system.

Also, the most important things - how this device looks like. There is a good functional case, not like DIY. the client trusts the device. And me, respectively

Yes - ESPHome In every house))))

Now the HLW8032 is working in my controller. Esphome does not have a standard driver for this chip, I used the driver from cse7766. Added the necessary coefficients for accurate calculation - and everything is displayed correctly. Unless the power consumption of the load is less than 100W, the current is displayed correctly and the power is not very accurate.

uart:
  rx_pin: 35
  baud_rate: 4800

sensor:
  - platform: cse7766
    update_interval: 2s
    current:
      name: "Atom Current"
      unit_of_measurement: A
      accuracy_decimals: 3
    voltage:
      name: "Atom Voltage"
      unit_of_measurement: V
      accuracy_decimals: 2
      filters:
        # Map from sensor -> measured value
        - calibrate_linear:
            - 0.0 -> 0.0
            - 500.0 -> 940.0
      
    power:
      name: "Atom Power"  
      unit_of_measurement: W
      accuracy_decimals: 2
      filters:      
              # Map from sensor -> measured value
        - calibrate_linear:
            - 0.0 -> 0.0
            - 5000.0 -> 9400.0

HLW8032_HA

2 Likes

It was an interesting project. Customer needs to remotely switch heating modes in the house. If no one is in the house, you need to maintain a temperature of 10 ÂşC, if you plan to get there - you need to preheat to 20 ÂşC and maintain at this level. In the future it is planned to use HA, and now there is only the Atom controller with ESPHome. In addition, there are only 2 wires to connect the temperature sensor.
Wrote a configuration file to switch the target temperature through a web server. I use a relay to turn on the boiler. There are red and white LEDs on the front panel of controller that I used to indicate the mode. Mode 10ÂşC - white LED, heating mode up to 20 ÂşC - red LED. Sensor DS18B20 is connected in a two-wire circuit, works well.
Now the customer decides that he will still automate, because he really liked the work of the controller.
Here is part of the configuration file. Here the operating modes and indication are set.

dallas:
  - pin: 33

sensor:
  - platform: dallas
    address: 0x9C3C01A8160D6928
    name: "Room temperature"
    id: temp1
    force_update: true

climate:
  - platform: thermostat
    name: "Thermostat"
    sensor: temp1
    id: climateid
    default_target_temperature_low: 10 °C
    heat_action:
      - switch.turn_on: boiler
    idle_action:
      - switch.turn_off: boiler

mcp23008:
  - id: 'mcp23008_hub'
    address: 32
     
switch:
  - platform: gpio
#    name: "White LED"
    id: whiteled
    pin:
      mcp23008: mcp23008_hub
      number: 3
      mode: OUTPUT
      inverted: False

  - platform: gpio
# red LED is connected to this gpio
    name: "Heating 20°C"
    on_turn_on:
      - switch.turn_off: whiteled    
      - climate.control:
          id: climateid
          mode: heat
          target_temperature: "20 °C"
    on_turn_off:
      - switch.turn_on: whiteled    
      - climate.control:
          id: climateid
          mode: heat
          target_temperature: "10 °C"
    pin:
      mcp23008: mcp23008_hub
      number: 2
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "OUT1"
    id: boiler
    pin:
      mcp23008: mcp23008_hub
      number: 0
      mode: OUTPUT
      inverted: False

I’m testing another cool controller - Atom Argon. 12 universal inputs, outputs - 18 relays 5A (50A starting current), LED-indicator of each output.
Supports i2c expansion module for 12 more such relays. That is, together it is 30 relays in the 9U case on a DIN rail!


mcp23008 and mcp23017 extenders are used here.

mcp23008:
  - id: 'mcp23008_hub'
    address: 32
    
mcp23017:
  - id: 'mcp23017_hub'
    address: 39
    
binary_sensor:
  - platform: gpio
    name: "IN1"
    pin:
      number: 33
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN2"
    pin:
      number: 32
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN3"
    pin: 
      number: 36
      inverted: True
    
  - platform: gpio
    name: "IN4"
    pin: 
      number: 37
      inverted: True
    
  - platform: gpio
    name: "IN5"
    pin: 
      number: 38
      inverted: True
    
  - platform: gpio
    name: "IN6"
    pin: 
      number: 39
      inverted: True
    
  - platform: gpio
    name: "IN7"
    pin: 
      number: 26
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN8"
    pin: 
      number: 25
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN9"
    pin: 
      mcp23008: mcp23008_hub
      number: 4
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN10"
    pin: 
      mcp23008: mcp23008_hub
      number: 5
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN11"
    pin: 
      mcp23008: mcp23008_hub
      number: 6
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN12"
    pin: 
      mcp23008: mcp23008_hub
      number: 7
      mode: INPUT_PULLUP
      inverted: True
      
switch:
  - platform: gpio
    name: "White LED"
    pin:
      mcp23008: mcp23008_hub
      number: 3
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "Red LED"
    pin:
      mcp23008: mcp23008_hub
      number: 2
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    pin: 18
    name: "Enable modules"
    
  - platform: gpio
    name: "K1"
    pin:
      mcp23017: mcp23017_hub
      number: 5
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "K2"
    pin:
      mcp23017: mcp23017_hub
      number: 4
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "K3"
    pin:
      mcp23017: mcp23017_hub
      number: 3
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "K4"
    pin:
      mcp23017: mcp23017_hub
      number: 2
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "K5"
    pin:
      mcp23017: mcp23017_hub
      number: 1
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "K6"
    pin:
      mcp23017: mcp23017_hub
      number: 0
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    pin: 10
    name: "K7"
      
  - platform: gpio
    pin: 5
    name: "K8"
      
  - platform: gpio
    pin: 9
    name: "K9"
      
  - platform: gpio
    pin: 4
    name: "K10"
    
  - platform: gpio
    name: "K11"
    pin:
      mcp23008: mcp23008_hub
      number: 0
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K12"
    pin:
      mcp23008: mcp23008_hub
      number: 1
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K13"
    pin:
      mcp23017: mcp23017_hub
      number: 8
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K14"
    pin:
      mcp23017: mcp23017_hub
      number: 9
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K15"
    pin:
      mcp23017: mcp23017_hub
      number: 10
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K16"
    pin:
      mcp23017: mcp23017_hub
      number: 11
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K17"
    pin:
      mcp23017: mcp23017_hub
      number: 12
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    name: "K18"
    pin:
      mcp23017: mcp23017_hub
      number: 13
      mode: OUTPUT
      inverted: False

1 Like

I have the opportunity to test the controller Atom Helium with relays and AC dimmers. Each dimmer is a pair of MOSFETs. The standard AC-dimming function in ESPHome does not work properly - at low brightness values ​​there is flicker. Tried PWM with different frequencies. When set to 100Hz, got smooth ignition and attenuation. Obviously, there is a slight desynchronization with the network frequency. I read on esphome.io that esp32 supports PWM frequency over 300kHz. Tried 30kHz. Flicker appeared only in a small brightness range, about 70 to 80%. Tried 50kHz. Works great !. MOSFETs is not heated at all. But so far I managed to try only one 10W lamp. I will check on 10 lamps. Engineers say that this can not be done - there will be strong interference, reduced lamp life, there will be strong heating of the MOSFETs. Has anyone tried to dimming this way? Any results? Do you have any thoughts on this?
Code for dimmer:

  - platform: ledc
    pin: 9
    frequency: 50000Hz
    id: OUT2

# Example usage in a light
light:
  - platform: monochromatic
    output: OUT2
    name: "OUT2"

Looks great! Did you try any other vendor of LED bulbs?

It was Horoz Expert-10. The Maxus 5W MR-16 lamp did not dimm ((

Why not dimm? Is it related to small power (5w) or specific vender?

i think this is a feature of the lamp driver

Today the manufacturer sent me a driver for the PCA9536 chip. Now I can use 4 controller buttons in my projects. I haven’t seen anyone use this chip in ESPHome before, so I’m posting an h-file and configuration code here.
I’lll need to make a handy menu to configure the controller ))

esphome:
  includes:
    - PCA9536.h
  name: atom
  platform: ESP32
  board: pico32
-------------------------

------------------------- 
  - platform: custom
    lambda: |-
     auto pca9536 = new PCA9536();
     App.register_component(pca9536);
     return {pca9536->but0, pca9536->but1, pca9536->but2, pca9536->but3};
    binary_sensors:
    - name: "Button 0"
    - name: "Button 1"
    - name: "Button 2"
    - name: "Button 3" 

PCA9536.h

#pragma once

#include "esphome.h"
#include "esphome/core/log.h"

namespace esphome {
namespace binary_sensor {

class PCA9536 : public PollingComponent, public BinarySensor { 
 private:
  static const int UPDATE_INTERVAL_MS = 200;	
  constexpr static const char *TAG = "PCA9536";
  static const int I2C_ADDRESS = 0x41;
 public:
  BinarySensor *but0 = new BinarySensor();
  BinarySensor *but1 = new BinarySensor();
  BinarySensor *but2 = new BinarySensor();
  BinarySensor *but3 = new BinarySensor();  
 
  PCA9536() : PollingComponent(UPDATE_INTERVAL_MS) {}
  void setup() override{
	ESP_LOGCONFIG(TAG, "Setting up PCA9536...");
    Wire.begin();
  }
  
  void update() override{
	uint8_t result = 0x00;
    Wire.beginTransmission(I2C_ADDRESS);
    Wire.write(0x00); //command read input 
    if(Wire.endTransmission()) {
       ESP_LOGD(TAG, "Transmission command error.");
       return;
    }
    Wire.requestFrom(I2C_ADDRESS, 1);
    if(Wire.available()==1) {
       result = Wire.read() & 0x0f;
    } else {
       ESP_LOGD(TAG, "Can't read data");
       return;
    }
    but0->publish_state(!(result & 0x01));
	but1->publish_state(!(result & 0x02));
	but2->publish_state(!(result & 0x04));
	but3->publish_state(!(result & 0x08));
  }
};

}
}

Most Atom series controllers have output sensors at the outputs to monitor the output current. All these sensors are connected to the MAX11616 ADC. There is already a driver for this chip for use in ESPHome. Here’s what it looks like in Home Assistant

esphome:
  includes:
    - LM75A.h
    - MAX11616.h
---------------
---------------
  - platform: custom
    lambda: |-
     auto max11616 = new MAX11616();
     App.register_component(max11616);
     return {max11616->adc0, max11616->adc1, max11616->adc2, max11616->adc3,
     max11616->adc4, max11616->adc5, max11616->adc6, max11616->adc7,
     max11616->adc8, max11616->adc9, max11616->adc10, max11616->adc11};
    sensors:
    - name: "MAX11616 ADC0"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC1"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC2"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC3"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC4"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC5"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC6"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC7"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC8"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC9"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC10"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC11"
      unit_of_measurement: V
      accuracy_decimals: 3

1 Like

And now I test the device with 8 relays 10A and with Hall sensors on each and 2 relays 5A. Here is a full yaml with settings of buttons, ADC, internal temperature sensor LM35 and energy meter. The customer wants to control the electric underfloor heating (5 zones of 1-1.2 kW) and facade lighting.

esphome:
  includes:
    - LM75A.h
    - MAX11616.h
    - PCA9536.h
  name: atom2
  platform: ESP32
  board: pico32

wifi:
  ssid: "ssid"
  password: "pass"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Atom Fallback Hotspot"
    password: "12345678"
    
captive_portal:

# Enable logging
logger:
  level: info

web_server:
  port: 80

# Enable Home Assistant API
api:

ota:

i2c:
  sda: 21
  scl: 19
  scan: True
  
time:
  - platform: sntp
    id: sntp_time
    servers:
      - 0.pool.ntp.org
      - 1.pool.ntp.org
      - 2.pool.ntp.org
      
   
mcp23008:
  - id: 'mcp23008_hub'
    address: 32
    
binary_sensor:
  - platform: gpio
    name: "IN1"
    pin:
      number: 33
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN2"
    pin:
      number: 32
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN3"
    pin: 
      number: 36
      inverted: True
    
  - platform: gpio
    name: "IN4"
    pin: 
      number: 37
      inverted: True
    
  - platform: gpio
    name: "IN5"
    pin: 
      number: 38
      inverted: True
    
  - platform: gpio
    name: "IN6"
    pin: 
      number: 39
      inverted: True
    
  - platform: gpio
    name: "IN7"
    pin: 
      number: 26
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN8"
    pin: 
      number: 25
      mode: INPUT_PULLUP
      inverted: True
    
  - platform: gpio
    name: "IN9"
    pin: 
      mcp23xxx: mcp23008_hub
      number: 4
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN10"
    pin: 
      mcp23xxx: mcp23008_hub
      number: 5
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN11"
    pin: 
      mcp23xxx: mcp23008_hub
      number: 6
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: gpio
    name: "IN12"
    pin: 
      mcp23xxx: mcp23008_hub
      number: 7
      mode: INPUT_PULLUP
      inverted: True
      
  - platform: custom
    lambda: |-
     auto pca9536 = new PCA9536();
     App.register_component(pca9536);
     return {pca9536->but0, pca9536->but1, pca9536->but2, pca9536->but3};
    binary_sensors:
    - name: "Button 0"
    - name: "Button 1"
    - name: "Button 2"
    - name: "Button 3"      

switch:
  - platform: gpio
    name: "White LED"
    pin:
      mcp23xxx: mcp23008_hub
      number: 3
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "Red LED"
    pin:
      mcp23xxx: mcp23008_hub
      number: 2
      mode: OUTPUT
      inverted: False
      
  - platform: gpio
    pin: 18
    name: "Enable modules"

  - platform: gpio
    pin: 4
    name: "OUT1"

  - platform: gpio
    pin: 9
    name: "OUT2"

  - platform: gpio
    pin: 5
    name: "OUT3"

  - platform: gpio
    pin: 10
    name: "OUT4"

  - platform: gpio
    pin: 2
    name: "OUT5"

  - platform: gpio
    pin: 22
    name: "OUT6"

  - platform: gpio
    pin: 23
    name: "OUT7"

  - platform: gpio
    pin: 27
    name: "OUT8"

  - platform: gpio
    name: "OUT9"
    pin:
      mcp23xxx: mcp23008_hub
      number: 1
      mode: OUTPUT
      inverted: False

  - platform: gpio
    name: "OUT10"
    pin:
      mcp23xxx: mcp23008_hub
      number: 0
      mode: OUTPUT
      inverted: False
      
font:
  - file: 'arial.ttf'
    id: font1
    size: 16
  - file: 'arial.ttf'
    id: font2
    size: 35
  - file: 'arial.ttf'
    id: font3
    size: 14
    
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    update_interval: 3s
    lambda: |-
      it.printf(64, 0, id(font1), TextAlign::TOP_CENTER, "i3 Engineering");
      it.strftime(0, 55, id(font2), TextAlign::BASELINE_LEFT ,"%H:%M", id(sntp_time).now());

uart:
  rx_pin: 35
  baud_rate: 4800

sensor:
  - platform: wifi_signal
    name: "WiFi Signal"
    update_interval: 5s
    
   - platform: cse7766
     update_interval: 2s
     current:
       name: "Atom Current"
       unit_of_measurement: A
       accuracy_decimals: 3
     voltage:
       name: "Atom Voltage"
       unit_of_measurement: V
       accuracy_decimals: 2
       filters:
          Map from sensor -> measured value
          - calibrate_linear:
             - 0.0 -> 0.0
             - 500.0 -> 940.0
     power:
       name: "Atom Power"  
       unit_of_measurement: W
       accuracy_decimals: 2
       filters:      
         Map from sensor -> measured value
         - calibrate_linear:
             - 0.0 -> 0.0
             - 5000.0 -> 9400.0
   
  - platform: custom
    lambda: |-
     auto lm75a = new LM75A();
     App.register_component(lm75a);
     return {lm75a};
    sensors:
      name: "LM75B Temperature"
      unit_of_measurement: В°C
      accuracy_decimals: 2
      
  - platform: custom
    lambda: |-
     auto max11616 = new MAX11616();
     App.register_component(max11616);
     return {max11616->adc0, max11616->adc1, max11616->adc2, max11616->adc3,
     max11616->adc4, max11616->adc5, max11616->adc6, max11616->adc7,
     max11616->adc8, max11616->adc9, max11616->adc10, max11616->adc11};
    sensors:
    - name: "MAX11616 ADC0"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC1"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC2"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC3"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC4"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC5"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC6"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC7"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC8"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC9"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC10"
      unit_of_measurement: V
      accuracy_decimals: 3
    - name: "MAX11616 ADC11"
      unit_of_measurement: V
      accuracy_decimals: 3

Hello,

I have in total 64 lights + shutters I want to control. Currently I have a Conson setup (really bad for smart integration) and looking for an update.

All my switches (on/off + up/down) work with 24v that sends an impuls to the module and then triggers the light on/off or the shutter goes up/down.
Can I use this system then? So when I press the button, the light goes on and I also see it in HomeAssistant?

Thanks in advance