Modbus / Send Register or Coil

Hey folks,

I am a bit of a modbus newb. So I got modbus to work, can read registers, doing sensors, all good.
My home electricity power system (e3dc) also controls my wallbox.

According to the manual:

Register: 40088
Name: WallBox_0_CTRL
Length: 1
Type: Uint16
Access: Read-Write

According to the specific Wallbox part in the manual:

Bit 0 : Wallbox present or not, access: Read only
Bit 1 : PV charging only or mixed operations: Read Write
Bit 2 : Abort Charging / Charging permitted: Read Write
[...]
Bit 13: unused

I just want to abort charging the car, so what I thought I should do is:

  - service: modbus.write_register
    data:
      address: 40089
      hub: e3dc
    data_template:
      value:
        - 1
        - 0
        - 1

Command is sent, but nothing is happening. I also tried the above with write coil instead.

What would be the correct way to set the Bit 2 of address 40088 correctly?

Thanks :slight_smile:

No one? :sob:
What about some basic coil sending?

Answering my own thread here if someone else is wanting to stop charging their E3DC Wallbox:

First, get yourself a new modbus sensor and read out address 40001:

      - name: E3DC MagicByte
        address: 40001
        slave: 1

Now check Home Assistant Sensor “E3DC MagicByte” it should be state “-7204”, which is E3DC if converted from Decimal to Hexadecimal. If you get anything else, increase or decrease the address by 1, then two until you get the right sensor reading. This is your offset. Say You get “-7204” on port 40000 your offset it -1.

Then create a new sensor:

      - name: E3DC Wallbox Settings
        address: 40088
        data_type: uint16
        slave: 1

Add your offset from the first step to the address (40087 if your offset it -1). Read the sensor. In my case: “47”. If you convert 47 to binary you get: 101111. Let untangle that:

-1 Wallbox present
-0 Use any power, not only solar
-1 Charging allowed
-1 Car charging
-1 Type2 Connector locked
-1 Type2 Connector in car

Now we want to interrupt the charging,

-1 Wallbox present
-0 Use any power, not only solar
-1 Charging allowed
-0 Car charging
-0 Type2 Connector locked
-1 Type2 Connector in car

Adjust to your liking. Converting 101001 to decimal yields 41.

Now you can stop your charging with this action:

action:
  - service: modbus.write_register
    data:
      address: 40088
      hub: e3dc
      value: 41

Again: Mind your offset here. If you want to send any other data, Convert your binary into a decimal and send that.

Done!

1 Like

Thx @creis for your work.

I’m having troubles with the write_register service.
I can read the e3dc wallbox settings and with

{{ states('sensor.e3dc_wallbox_settings') | int // (2**N) % 2}}

(where N = a number from0-5 for the 6 Bits) I can extract the state of every single bit and created binary sensors for this. See the below Example for the state of “Use any power, not only solar” as you stated above.

- binary sensor:
  - name: wbbit1
    unique_id: wbbit1
    state: >
      {{ states('sensor.e3dc_wallbox_settings') | int // (2**1) % 2}}

Now, I’d like to change the settings with:

service: modbus.write_register
data:
  address: 40087
  hub: e3dc
  value: 51

and I recieve the follwoing:

Logger: homeassistant
Source: components/modbus/modbus.py:398
First occurred: 13:17:15 (2945 occurrences)
Last logged: 14:55:30

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/modbus/sensor.py", line 104, in async_update
    raw_result = await self._hub.async_pymodbus_call(
  File "/usr/src/homeassistant/homeassistant/components/modbus/modbus.py", line 421, in async_pymodbus_call
    result = await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/homeassistant/homeassistant/components/modbus/modbus.py", line 398, in _pymodbus_call
    result = entry.func(address, value, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/pymodbus/client/mixin.py", line 100, in read_holding_registers
    return self.execute(
  File "/usr/local/lib/python3.10/site-packages/pymodbus/client/base.py", line 192, in execute
    return self.transaction.execute(request)
  File "/usr/local/lib/python3.10/site-packages/pymodbus/transaction.py", line 159, in execute
    response, last_exception = self._transact(
  File "/usr/local/lib/python3.10/site-packages/pymodbus/transaction.py", line 273, in _transact
    packet = self.client.framer.buildPacket(packet)
  File "/usr/local/lib/python3.10/site-packages/pymodbus/framer/socket_framer.py", line 217, in buildPacket
    data = message.encode()
  File "/usr/local/lib/python3.10/site-packages/pymodbus/register_read_message.py", line 31, in encode
    return struct.pack(">HH", self.address, self.count)
struct.error: 'H' format requires 0 <= number <= 65535

Tried different values of course.
Actually I use a switch to perform the action as follows:

##Template switches
switch:
  - platform: template
    switches:
      solarbetrieb:
        unique_id: solarbetrieb
        friendly_name: Solarbetrieb
        value_template: "{{ is_state('binary_sensor.wbbit1', 'on') }}"
        turn_on:
          service: modbus.write_register
          data:
            hub: e3dc
            address: 40087
            value: "{{ states('sensor.e3dc_wallbox_settings') | int + 2 }}"
        turn_off:
          service: modbus.write_register
          data:
            hub: e3dc
            address: 40087
            value: "{{ states('sensor.e3dc_wallbox_settings') | int - 2 }}"

Which does not seem to make any problems itself. As you notice, the offset for me is -1.

Do you or others have any idea?

Cheers,
Simon

@ssy
I did it as follows

script called from a lovelace card

alias: e3dc Wallbox laden toggle
sequence:
  - if:
      - condition: state
        entity_id: binary_sensor.e3dc_wallbox_0_charging_open
        state: "off"
    then:
      - service: script.write_register_turn_off_bit
        data:
          bit: 3
          hub: e3dc
          unit: 1
          address: 40087
          sensor_value: sensor.e3dc_wallbox_0_ctrl
    else:
      - service: script.write_register_turn_on_bit
        data:
          bit: 3
          hub: e3dc
          unit: 1
          address: 40087
          sensor_value: sensor.e3dc_wallbox_0_ctrl
mode: single

here the two simple ‘helper’ scripts:

Write Register turn on bit

alias: Write Register turn on bit
sequence:
  - service: modbus.write_register
    data:
      hub: "{{ hub }}"
      unit: "{{ unit }}"
      address: "{{ address }}"
      value: >-
        {{ states(sensor_value) | int(default=0) | bitwise_or(2 ** (bit | int -
        1)) }}
  - service: homeassistant.update_entity
    data:
      entity_id: "{{ sensor_value }}"

Write Register turn off bit

alias: Write Register turn off bit
sequence:
  - service: modbus.write_register
    data:
      hub: "{{ hub }}"
      unit: "{{ unit }}"
      address: "{{ address }}"
      value: >-
        {{ states(sensor_value) | int(default=0) | bitwise_and(65535 - (2 **
        (bit | int - 1))) }}
  - service: homeassistant.update_entity
    data:
      entity_id: "{{ sensor_value }}"

and you need the modbus sensors, here the one needed for controlling the wallbos

# -----------
# modbus E3DC
# magic byte
#    expected at 400001
#    found at 40000
#    => offset -1
# -----------
  - name: e3dc
    type: tcp
    host: 192.168.178.111
    port: 502
    delay: 5
    timeout: 5
    sensors:
      - name: E3DC Wallbox 0 CTRL
        unique_id: e3dc_wallbox_0_ctrl
        data_type: uint16
        address: 40087```