Broadlink S1C Kit sensors in HA using python and MQTT

Haven’t spent more time on this, I replaced my s1c with RF sensors using the OpenMQTTGateway

I’ve got all the sensors showing in Home Assistant and the door sensor is working fine with my automation however I cannot get the motion sensor to work with my automation. Did anyone come across any issues with the motion sensor and what did you do to overcome them?

never mind. Not sure what I did but the state was showing incorrect message but it’s showing right now and working. Thanks for writing this script :slight_smile:

Hello guys, would this solution work on hassio on Raspberry Pi (resinos-hassio)?

Don’t know I use hassbian

1 Like

Starting from Bestlibre`s addon python_exec i was able to make a addon that is working on hassio. I am not a coder so i give all the credit for the addon to Bestlibre.

So in the addons folder of hassio we need to create a folder s1c. In that folder we need to create 3 files.

  1. Dockerfile
    In that file i copied the content from the python_exec addon and added some other lines.

ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
RUN apk add --no-cache jq
RUN apk add --no-cache py2-pip
RUN apk add --no-cache clang
RUN apk add --no-cache libgcc
RUN apk add --no-cache gcc-gnat
RUN apk add --no-cache libgc++
RUN apk add --no-cache g++
RUN apk add --no-cache make
RUN apk add --no-cache libffi-dev
RUN apk add --no-cache openssl-dev
RUN apk add --no-cache python2-dev
RUN apk add --no-cache mosquitto
RUN apk add --no-cache mosquitto-dev
RUN apk add --no-cache mosquitto-libs
RUN apk add --no-cache mosquitto-clients
RUN pip install pyaes
RUN pip install broadlink
RUN pip install pycrypto
RUN apk add --no-cache
jq
py-pip
python
python-dev
python3
mosquitto
mosquitto-clients
python3-dev
&& pip install -U pip
&& pip3 install -U pip
&& pip install -U virtualenv
COPY run.sh /
RUN chmod a+x /run.sh
CMD [ “/run.sh” ]

  1. config.json

{
“name”: “Name of the Addon”,
“version”: “x.x.x”,
“slug”: “s1c”,
“description”: “Hass.io addon for the Broadlink Python S1C Script.”,
“startup”: “application”,
“boot”: “auto”,
“ports”: {“xxxx/tcp”: null},
“options”: {“code”: null,
“requirements”: },
“schema”: {“code”: “str”,
“requirements”: [“str”],
“clean”: “bool?”},
“map”: [“share”]
}

  1. run.sh

#!/bin/bash
set -e
CONFIG_PATH=/data/options.json
requirements=$(cat /data/options.json | jq -r ‘if .requirements then .requirements | join(" ") else “” end’)
code=$(cat /data/options.json | jq -r ‘.code’)
clean=$(cat /data/options.json | jq -r ‘.clean //empty’)
py2=$(cat /data/options.json | jq -r ‘.python2 // empty’)
PYTHON=$(which python3)
if [ “${py2}” == “true” ];
then
PYTHON=$(which python2)
fi
if [ -n “$requirements” ];
then
if [ “$clean” == “true” ];
then
rm -rf /data/venv/
fi
if [ ! -f “/data/venv/bin/activate” ];
then
mkdir -p /data/venv/
cd /data/venv
virtualenv -p ${PYTHON} .
. bin/activate
fi
pip install -U ${requirements}
fi
python ${code}

Do not forget to make the run.sh executable. Install the addon and be patient cause it will take some time. Start the addon after modifying the options:

{
“code”: “/share/s1c.py”,
“requirements”: [
“broadlink”
]
}

The s1c.py file in my case is in the share folder of the hassio. Also i`ve done some modifications with the s1c.py cause there were some python errors about the time.ctime()

import broadlink
import time, os, datetime
devices = broadlink.S1C(host=(“x.x.x.x”,80), mac=bytearray.fromhex(“B4430Dxxxxxx”)) # Change to your S1C IP Address and S1C Mac Address
devices.auth()
sens = devices.get_sensors_status()
now = time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime(time.time())) #This is a line added by me
old = sens
while 1:
try:
sens = devices.get_sensors_status()
for i, se in enumerate(sens[‘sensors’]):
if se[‘status’] != old[‘sensors’][i][‘status’]:
sName = se[‘name’]
sType = se[‘type’]
if sType == “Door Sensor” and str(se[‘status’]) == “0” or sType == “Door Sensor” and str(se[‘status’]) == “128”: # Instead of sType you can test for sName in case you have multiple sensors
print("Time ") + str(now) + ": Door closed: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/entrance_door’ -u admin -P password -m " + “Closed”) # change the ip address, user name and password for your mosquitto server
elif sType == “Door Sensor” and str(se[‘status’]) == “16” or sType == “Door Sensor” and str(se[‘status’]) == “144”:
print("Time “) + str(now) +”: Door opened: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/entrance_door’ -u admin -P password -m " + “Open”)
elif sType == “Door Sensor” and str(se[‘status’]) == “48”:
print("Time “) + str(now) +”: Door Sensor tampered: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/entrance_door’ -u admin -P password -m " + “Tampered”)
elif sType == “Motion Sensor” and str(se[‘status’]) == “0” or sType == “Motion Sensor” and str(se[‘status’]) == “128”:
print("Time “) + str(now) +”: No Motion: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/motion_sensor’ -u admin -P password -m " + “No_motion”)
elif sType == “Motion Sensor” and str(se[‘status’]) == “16”:
print("Time “) + str(now) +”: Motion Detected: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/motion_sensor’ -u admin -P password -m " + “Motion_Detected”)
elif sType == “Motion Sensor” and str(se[‘status’]) == “32”:
print("Time “) + str(now) +”: Motion Sensor Tampered: " + str(se[‘status’])
os.system("mosquitto_pub -h x.x.x.x -p 1883 -t ‘sensors/s1c/motion_sensor’ -u admin -P password -m " + “Tampered”)
old = sens
except:
continue

I also modified the

print time.ctime()

with the

print("Time ") + str(now)


3 Likes

@gabriel.colceriu thank you very for sharing. I kinda tried to follow your instructions and it works. Well, at least the python-exec-broadlink-s1c add-on receives the values from the sensors but it cannot contact the mqtt broker. I keep receiving a message like:
Sh mosquitto_pub: not found
But if I try to make a mosquitto_pub command in a ssh shell it works correctly. Any idea?

Yes i do know what`s the problem. Add another line on the Dockerfile installing the mosquitto-clients

RUN apk add --no-cache mosquitto-clients

Remember that the addon is running in a docker, which is different from the ssh shell you are trying the mosquitto_pub command.
I will modify the docker file in the original post also.

After last night I also saw another problem with the time on the logs. Its always the same time and its the time when you start the add-on. Like I said earlier, I am not a coder, so any help with the s1c. by file and the time. ctime problem will be appreciated. That does not affect the mqtt time and the time shown in homeassistant.

You are right, adding the mosquitto clients it works. I’m not really a programmer too, but I’ll have a look later. Anyway, thank you very much for helping

@NightRanger

Thanks so much for this instruction but can I know where shall I put the file sensors.yaml and customize.yaml?

when I run s1c.py, I can see the result, but I don’t know how to show in on the page of home assistant.

You need to add the appropriate entities in a group / view

thanks so much for kind reply and still I can’t the sensors shown on the screen.

which mqtt broker is required for this component? I use mosquitto with below entry in the configuration.yaml, is it the correct way?

mqtt:
broker: core-mosquitto

and my full entry in the sensor part of the configuration.yaml is as below, is it right? thanks in advance!

sensor:

  • platform: broadlink
    host: 192.168.1.70
    mac: ‘34:EA:34:B2:B9:A4’
    monitored_conditions:

    • temperature
    • humidity
    • air_quality
    • light
    • noise
  • platform: command_line
    name: Tide
    command: “python3 /home/hsie/.homeassistant/custom_components/tide.py”

  • platform: mqtt
    state_topic: “sensors/s1c/entrance_door”
    name: “entrance_door_sensor”

  • platform: mqtt
    state_topic: “sensors/s1c/motion_sensor”
    name: “motion_sensor”

It uses mosquito broker, regarding the the visibilty of the sensor make sure you can see the entity in the developers tools states section and that the status of the sensor change whenever theres motion or door is opened after that put it in a view,

This is my config from the config.yaml file

mqtt:
  broker: 10.0.0.35
  port: 1883
  client_id: home-assistant-1
  username: !secret mqtt_username
  password: !secret mqtt_password

Amazing!

I’ve been looking for a way to integrate my s1c sensors with ha.
I’ve followed the instructions by @NightRanger and @gabriel.colceriu in an hassio 0.55 environment,
Everything works very well! :grin:

I just made a couple of changes to s1c.py script…

The first and most important change was editing the mqtt topic so that it would be more dynamic so I can use multiple sensors of the same type with no editing required on the script side.
The new topic is “sensors/s1c/” concatenated with the sensor name in lowercase replacing white spaces with underscores. For example:
Sensor Name: Bedroom Door
Topic: sensors/s1c/bedroom_door.

The second change I’ve made was iterating thru the original sensors once at startup without checking if the status has changed.
The reason for this is the inability of the mqtt sensors in ha to retain their values after a reboot.
So I figured I can update them once at startup…
The thing is… it’s not working, as far as I can tell, the s1c addon is initialized before either the mqtt broker or the sensors component in ha, which means the update isn’t working.
I’ll try to think of another way to accomplish that, maybe running a similar script within an automation when ha starts…

2 Likes
import broadlink
import time, os, datetime

mosquitto_address = ""
mosquitto_port = ""
mosquitto_user = ""
mosquitto_password = ""
broadlink_s1c_ip = ""
broadlink_s1c_mac = ""

devices = broadlink.S1C(host=(broadlink_s1c_ip, 80), mac=bytearray.fromhex(broadlink_s1c_mac))
devices.auth()

sens = devices.get_sensors_status()
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
old = sens


def checkSensor(v_type, v_name, v_status):
    if v_type == "Door Sensor" and v_status in ("0", "128"):
        sendToMosquito(v_name, "Closed")
    elif v_type == "Door Sensor" and v_status in ("16", "144"):
        sendToMosquito(v_name, "Open")
    elif v_type == "Door Sensor" and v_status == "48":
        sendToMosquito(v_name, "Tampered")
    elif v_type == "Motion Sensor" and v_status in ("0", "128"):
        sendToMosquito(v_name, "No_motion")
    elif v_type == "Motion Sensor" and v_status == "16":
        sendToMosquito(v_name, "Motion_Detected")
    elif v_type == "Motion Sensor" and v_status == "32":
        sendToMosquito(v_name, "Tampered")
    return


def sendToMosquito(v_deviceName, v_payload):
    os.system("mosquitto_pub -h " + mosquitto_address + " -p " + mosquitto_port + " -t 'sensors/s1c/" + v_deviceName + "' -u " + mosquitto_user + " -P " + mosquitto_password + " -m " + v_payload)
    return

#for k, se in enumerate(sens['sensors']):
#    checkSensor(se['type'], ((se['name']).replace(" ", "_")).lower(), str(se['status']))


while 1:
    try:
        sens = devices.get_sensors_status()
        for i, se in enumerate(sens['sensors']):
            if se['status'] != old['sensors'][i]['status']:
                checkSensor(se['type'], ((se['name']).replace(" ", "_")).lower(), str(se['status']))
                old = sens
    except:
        continue
1 Like

@TomerFi You can use binary sensor and automations for the retain option

Here’s an example:

# binary sensor

- platform: mqtt
  name: "Front door sensor"
  qos: 0
  state_topic: "home/entrance/door"
  payload_on: "111111"
  payload_off: "222222"
  device_class: opening
  
  # automations
  
  - alias: 'Front Door Sensor Opened Retain'
  initial_state: 'on'
  trigger:
    platform: mqtt
    topic: sensors/s1c/frontdoor
    payload: 111111
  action:
    service: mqtt.publish
    data:
      topic: 'home/entrance/door'
      payload: '111111'
      retain: 'true'


- alias: 'Front Door Sensor Closed Retain'
  initial_state: 'on'
  trigger:
    platform: mqtt
    topic: sensors/s1c/frontdoor
    payload: 222222
  action:
    service: mqtt.publish
    data:
      topic: 'home/entrance/door'
      payload: '222222'
      retain: 'true’

thanks so much and now it works!

1 Like

@NightRanger
Very cool, thank you!
Please correct me if I’m wrong here, but as far as I can see this configuration will help me retain the the latest state of the door and not the current state, which means that in the following order of events the sensor will show the wrong state:

1- The door is closed and the sensor shows “Closed”.
2- The ha system goes down.
3- I open the door.
4- I boot up my ha system.
5- The sensor will show the door is “Closed” even though the door is actually open, to correct this I’ll have to close the door and reopen it so that the sensor will change to “Open”.

There are a couple of ways to accomplish that,
You can also have an automation that updates a designated variable or an input_text object each time the mqtt sensor changes its state as long as the state exists, and have a template sensor which shows the value of the variable or the input_text object, and this will be the sensor you show in your frontend. I did something similar to this for my AC.

I’m going to try something else, I’ll create another version of your script that will scan the sensors and publish the correct topic for the door state once, I’ll then create an automation that will call this script each time the ha system starts, which means my mqtt sensors will always show the correct state.
I think this will be a great addition to an excellent script done by you.