USB relay - converting analog output to binary sensor

Hello, I have a 8 channel usb relay board, with FTDI ft232rl controller. Controlling those relays is very simple, you can just send a character corresponding to number of the relay. For example: “1” turns on relay no.1, sending it again turns it off. etc.

There is a working configuration:

shell_command:
    przek1: echo -e -n '1' >> /dev/ttyUSB0 
    przek2: echo -e -n '2' >> /dev/ttyUSB0
    przek3: echo -e -n '3' >> /dev/ttyUSB0
    przek4: echo -e -n '4' >> /dev/ttyUSB0
    przek5: echo -e -n '5' >> /dev/ttyUSB0
    przek6: echo -e -n '6' >> /dev/ttyUSB0
    przek7: echo -e -n '7' >> /dev/ttyUSB0
    przek8: echo -e -n '8' >> /dev/ttyUSB0

The serial port also returns an analog number from 0 to 255, for example:
relay no.1 is on = 1
relay no.2 is on = 2
relay no.8 is on = 128
relay no.1 and no.8 = 128 + 1 = 129

So the question is, is it possible to create a binary sensor that can tell which relays are on based on the decimal output? I know you can create 64 combinations of “or’s” for each relay but that would be very, very, inefficient and time consuming way of doing it.

It seems that bitwise operation doesn’t exists in HA Jinja

I’d go with the way binary is constructed.
If you take any number and want to convert it, it is like so
You do a constant division by 2 and keep the remainder until you reach zero

49 / 2 = 24 (remainder = 1)
24 / 2 = 12 (remainder = 0)
12 / 2 = 6 (remainder = 0)
6 / 2 = 3 (remainder = 0)
3 / 2 = 1 ( remainder = 1)
1 / 2 = 0 ( remainder = 1)

So, 49 is bit 1, 5 and 6 set

17 / 2 = 8 ( remainder = 1)
8 / 2 = 4 ( remainder = 0)
4 / 2 = 2 ( remainder = 0)
2 / 2 = 1 ( remainder = 0)
1 / 2 = 0 ( remainder = 1)

So, 17 is bit 1 and 5 set

I’ll come back later to you to help you with a Jinja template solution if you did not get it yourself.

First throw:

{% set relay_status = 233 %}
starting with {{ relay_status }}
bit 1 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 2 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 3 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 4 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 5 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 6 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 7 is {{ relay_status % 2 }} {% set relay_status = (relay_status / 2) | int %}
bit 8 is {{ relay_status % 2 }}

In Developer Tools > Template
Gives

starting with 233
bit 1 is 1 
bit 2 is 0 
bit 3 is 0 
bit 4 is 1 
bit 5 is 0 
bit 6 is 1 
bit 7 is 1 
bit 8 is 1

Final solution (?)

Create an input_number helper, to initialise with the value returned by your serial port (I let this part for you).
Lets call it input_number.relay in this exemple.
Create 8 input_boolean helpers named input_boolean.relay1 to input_boolean.relay8 in this exemple.

Automation:

alias: Bitwise AND
description: Bitwise AND
trigger:
  - platform: state
    entity_id:
      - input_number.relay
action:
  - alias: Repeat the sequence 8 times
    repeat:
      sequence:
        - if:
            - condition: template
              value_template: "{{ states('input_number.relay') | int % 2 == 1 }}"
          then:
            - service: input_boolean.turn_on
              target:
                entity_id: |
                  input_boolean.relay{{repeat.index}}
          else:
            - service: input_boolean.turn_off
              target:
                entity_id: |
                  input_boolean.relay{{repeat.index}}
        - service: input_number.set_value
          target:
            entity_id: input_number.relay
          data:
            value: "{{ (states('input_number.relay') | int(0) / 2) | int(0) }}"
      until:
        - condition: template
          value_template: "{{ repeat.index == 8 }}"
mode: single

Gives this:

1 Like

Thank you very much! This is a solution I’ve been looking for. I am fairly new to HA and I’m still learning this “Jinja” thing.

So, I copied the automation you wrote me above, created all the helpers and made another automation to set the input_number value to value of sensor.kartausb. Just like that:

action:
  - service: input_number.set_value
    data:
      value: ('sensor.kartausb')
    target:
      entity_id: input_number.relay

Then, I created buttons based on those helper relays, each button after clicking sends a command.

The only problem left to solve: If you turn off last relay, it stays on even though input_value is 0.
I’m thinking of making yet another automation turning off group of those input_boolean helpers after sensor.kartausb is 0.

No, it should work like this.
The reason is that HA is smart.
As the value of the input_number is 0 and you set it to 0, there is no change, so the automation is not triggered.

So, in the automation that set the input_number, I’d put an additional action

- if:
  - condition: numeric_state
    entity_id: input_number.relay
    below: 1
  then:
  - service: automation.trigger
    data: {}
    target:
      entity_id: automation.bitwise_and

That should force the automation to start anyway

EDIT: Pay attention to indentation, -if: should be at the same level as your - service: input_number.set_value

Great, added this and everything works flawlessly. Thanks again.

1 Like