Integration : Home assistant - themactep/thingino-firmware GitHub Wiki

Native integration (thingino-ha)

Thingino ships a Home Assistant integration based on MQTT discovery: the camera registers itself as a device in HA and its entities appear automatically, with no YAML on the HA side. State changes are pushed over MQTT, so no polling or rest_command is needed. The REST and ONVIF recipes further down this page remain useful on older firmware.

Requirements

  • An MQTT broker reachable by both the camera and HA (for example the Mosquitto add-on).
  • The MQTT integration enabled in HA (Settings -> Devices & Services -> Add Integration -> MQTT).

The thingino-ha package is part of the core build, so it is already on the camera. It stays inactive until you enable it.

Setup

In the camera web UI, open Services -> Home Assistant:

  1. Fill in the MQTT Broker section. The host is required. Other empty fields (port, username, password) fall back to the mqtt_sub settings.
  2. Tick Enable Home Assistant integration.
  3. Choose which entities to expose, then save. The service restarts on save.

The device shows up in HA within a few seconds.

From the shell, the same thing:

jct /etc/thingino.json set ha.mqtt.host 192.168.1.10
jct /etc/thingino.json set ha.enabled true
/etc/init.d/S93ha restart

Entities

Each entity can be turned on or off with an ha.enable_<name> key, or from the web UI.

Entity Type Key Default
Motion detected binary sensor enable_motion on
Doorbell pressed binary sensor enable_doorbell off
Motion Guard switch enable_motion_guard on
IR cut filter switch enable_ircut on
Day/Night mode select enable_daynight on
Day/Night state (mode applied) sensor enable_daynight_state on (ciao only)
Scene brightness (%) sensor enable_brightness on (ciao only, needs daynightd)
Privacy screen switch enable_privacy on
Color mode switch enable_color on
IR LED 850 nm switch enable_ir850 on
IR LED 940 nm switch enable_ir940 on
White light switch enable_white_light on
Floodlight (Wyze v1, 1-100% brightness) light enable_floodlight off (ciao only)
Lamp socket (Wyze) switch enable_lamp_socket on
Live view (still image) camera enable_live_view on (off on ciao)
Snapshot button enable_snapshot on
Reboot button enable_reboot off
PTZ up/down/left/right/home buttons enable_ptz off
Firmware version / build date sensors enable_firmware_version, enable_firmware_timestamp on
WiFi signal sensor enable_rssi on
ISP gain sensor enable_gain off
Firmware update update enable_ota off

The lamp socket entity also requires lamp_socket.enabled.

The Firmware update entity appears under Settings -> Updates in HA and installs new releases with a config-preserving upgrade (sysupgrade -p).

Other settings

Key Default Purpose
ha.discovery_prefix homeassistant Must match the HA MQTT discovery prefix
ha.device_name hostname Device name in HA
ha.state_interval 15 (30 on ciao) Seconds between state refreshes
ha.camera_interval 60 Seconds between live view images
ha.discovery_interval 3600 Discovery republish period
ha.ota_check_interval 21600 Seconds between release checks

MQTT topics live under cameras/<hostname>/, and entity unique IDs include the hostname. Renaming the camera therefore creates new entities in HA, so pick the final hostname before enabling the integration.

Troubleshooting

logread | grep ha-
mosquitto_sub -h <broker> -v -t 'cameras/<hostname>/#'

Full reference (topics, payloads): docs/thingino/services/homeassistant.md

ONVIF

To configure camera in home assistant, add onvif integration. Then add a new camera and let it autodiscover. In my case autodiscovery failed but it prompted me for IP address of camera. Once entering auth details it added it correctly.

When manually setting up the camera with ONVIF, the port will be "80" and the default username and password is "thingino". The login credentials can be changed from the settings > RTSP/ONVIF Access page of the Thingino interface.

The URL to get snapshot from camera is

http://thingino:thingino@[ipOfYourCamera]/image.jpg

Add white led in home assistant

For now it requires polling to get status.


light:
  - platform: template
    lights:
      z55_light:
        unique_id: "z55_light"
        turn_on:
          - action: rest_command.z55_camera_light_on
        turn_off:
          - action: rest_command.z55_camera_light_off
        #value_template: "{{ is_state('binary_sensor.z55_light_status', 'on') }}"
        value_template: "{{ states('binary_sensor.z55_light_status') }}"
template:
  - unique_id: z55_light_status_template
    trigger:
      - trigger: time_pattern
        seconds: /30
    action:
      - action: rest_command.z55_camera_light_status
        response_variable: z55_response
    binary_sensor:
      - name: z55_light_status
        unique_id: z55_light_status
        state: >
          {{ z55_response['content']['message']['white'] == 1 }}

rest_command:
  z55_camera_light_on:
    url: "http://z55.home/x/json-imp.cgi?cmd=white&val=1"
    username: root
    password: MyRootPassword
    verify_ssl: false
    method: get

  z55_camera_light_off:
    url: "http://z55.home/x/json-imp.cgi?cmd=white&val=0"
    username: root
    password: MyRootPassword
    verify_ssl: false
    method: get

  z55_camera_light_status:
    url: "http://z55.home/x/json-imp.cgi?cmd=white&val=read"
    username: root
    password: MyRootPassword
    verify_ssl: false
    method: get
    headers:
      Accept: "*/*"

Add a Picture Glance Card with PTZ Controls

The ONVIF implementation in Home Assistant does not expose PTZ controls as entities. You will need to add custom code to add the controls. The following is the full YAML for a Picture Glance Card with PTZ control. Be sure to update with the proper camera entity name.

camera_view: live
fit_mode: cover
type: picture-glance
title: Cinnado T23
image: http://thingino:[email protected]/image.jpg
camera_image: camera.cinnado_profile_1
entities:
  - entity: camera.cinnado_profile_1
    name: Pan Left
    icon: mdi:arrow-left
    tap_action:
      action: call-service
      service: onvif.ptz
      service_data:
        entity_id: camera.cinnado_profile_1
        pan: LEFT
        speed: 1
        distance: 0.01
        move_mode: ContinuousMove
  - entity: camera.cinnado_profile_1
    name: Tilt Up
    icon: mdi:arrow-up
    tap_action:
      action: call-service
      service: onvif.ptz
      service_data:
        entity_id: camera.cinnado_profile_1
        tilt: UP
        speed: 1
        distance: 0.01
        move_mode: ContinuousMove
  - entity: camera.cinnado_profile_1
    name: Tilt Down
    icon: mdi:arrow-down
    tap_action:
      action: call-service
      service: onvif.ptz
      service_data:
        entity_id: camera.cinnado_profile_1
        tilt: DOWN
        speed: 1
        distance: 0.01
        move_mode: ContinuousMove
  - entity: camera.cinnado_profile_1
    name: Pan Right
    icon: mdi:arrow-right
    tap_action:
      action: call-service
      service: onvif.ptz
      service_data:
        entity_id: camera.cinnado_profile_1
        pan: RIGHT
        speed: 1
        distance: 0.01
        move_mode: ContinuousMove
  - entity: binary_sensor.cinnado_motion_alarm

Note for Wuuk camera owners: The PTZ examples using "distance: 0.01" don't seem to work -- the camera ignores distance and moves too far. Using "continuous_duration: 0.07" instead provides accurate, controlled movement.

Set Motion Guard

Since Thingino doesn't expose Motion Guard settings via the ONVIF interface, Home Assistant shows an error when using the built-in Enable/Disable Motion Detection actions. While enabling or disabling the Motion Guard service in Thingino is only possible through a websocket, changing the notification target is possible via a simple HTTP GET request.

The URL is http://[user]:[password]@[camera IP address]/x/json-motion.cgi?target=[target]&state=[true|false]

Where the target is one of: send2email | send2ftp | send2mqtt | send2telegram | send2webhook | send2ntfy | send2gphotos

See also the source in json-motion.cgi

WebRTC integration

Some users may encounter a problem where the WebRTC integration (https://github.com/AlexxIT/WebRTC) unexpectedly falls back to MSE instead of establishing a proper WebRTC stream. This behavior is often caused by the camera streaming audio using the AAC codec. If you run into this issue, update the camera's audio codec from AAC to OPUS via the camera's web interface: "Settings → Streamer/OSD → Audio"

If HTTPS is properly configured in your go2rtc setup (https://github.com/AlexxIT/go2rtc), the configuration below enables two-way audio, provided that the camera’s microphone is turned on in the web interface. (tested with a WUUK camera)

type: custom:webrtc-camera
url: wuuk1   # this is the stream defined in your "streams" session in go2rtc.yaml
mode: webrtc
media: video,audio,microphone

Remark: On my WUUK camera, the built-in speaker wasn’t loud enough, and it seems that there is no speaker volume control exposed in the web UI. I was able to increase the volume by connecting to the camera via SSH and editing /etc/iad.json. In the AO_attributes section, raise the SetVol value (for example, to 90) to make the speaker significantly louder after a reboot.

Two-Way-Audio in Home Assistant leveraging WebRTC/go2rtc

This is an example about how to integrate in a WebRTC card, two-way-audio capabilities with Cinnado D1 and Thingino. Initially Prudynt initiate the rtsp backchannel, so nothing need to be configure additionally in go2rtc nor in the camera. In this example audio configuration is setup as ACC, so if you want to hear properly the audio in the webrtc card, best is convert to opus the audio stream as shown and do not change in the camera.

Captura de pantalla 2026-10-29 113743

Please note that in the web browser, you will have problems with the security configuration so the best to allows webrtc/go2rtc enable the backchannel stream is using the HA app in the mobile phone accessing the HA server through https://xxxxxxx.duckdns.org for example

As webrtc doesn't have posibility to handdle mic dinamically, I create a vertical-stack with one webrtc-camera card enabling video, audio and a custom card based in webrtc enabling only mic when button is clicked.

Captura de pantalla 2026-10-29 113254

I created a custom component called cinnado-talk-card.js-->https://gist.github.com/Mrivilla/3406cff8f3eda0509fa5b0aecff25bc5 that need to be added as resource in HA, Configuration-->Dashboards->Resources as shown in the picture. Previously the cinnado-talk-card.js need to be copied manually in /config/www in your HA server

Captura de pantalla 2026-10-29 130717

On that way you can speak at the sametime you are able to heard the audio.

Tutorial: Dynamic REST Commands for WUUK / Thingino Cameras

Manage multiple WUUK / Thingino cameras in Home Assistant using a single rest_command, while keeping all IP addresses cleanly stored in a separate YAML file.

This example shows how to restart the streamer on several cameras without performing a full device reboot. The same approach can be adapted to trigger any other commands exposed in the webUI. Using this setup, you will be able to:

  • Store all camera IPs in one file
  • Assign each camera a simple alias (wuuk1, wuuk2, etc.)
  • Call a generic REST command dynamically
  • Create buttons that restart the streamer in any camera
  • Avoid duplicating IPs everywhere

To find the URL used by your camera’s Restart streamer button in the web interface, open the camera’s web UI in your browser. Then, move your mouse over the Setting -> Streamer/OSD -> Restart streamer button (without clicking it). Your browser should show the target address, usually at the bottom of the window.

For example, in the web interface of one of my cameras, I click on the Tools menu in the top toolbar and then hover over "Restart streamer." The browser shows the URL: http://192.168.1.2/x/config-streamer.cgi?do=restart

In this case, 192.168.1.2 is the IP address of the camera, and /x/config-streamer.cgi?do=restart is the endpoint we will use in the Home Assistant REST command.


✅ 1. Create ip.yaml (Alias → IP Mapping)

Create a file named ip.yaml in your Home Assistant config directory (usually /config on most installs):

wuuk1: 192.168.1.2
wuuk2: 192.168.1.3
wuuk3: 192.168.1.4

This file contains all camera IPs centrally.
You’ll use these aliases (wuuk1, wuuk2, etc.) everywhere else.


✅ 2. Expose the Mapping Using a Template Sensor

Add this block to your configuration.yaml:

template:
  - sensor:
      - name: "Camera IP Map"
        unique_id: camera_ip_map
        state: "ok"
        attributes: !include ip.yaml

Home Assistant will create an entity:

  • Entity ID: sensor.camera_ip_map
  • Attributes: All camera names and their IPs from ip.yaml

Example attributes (in Developer Tools → States):

wuuk1: 192.168.1.2
wuuk2: 192.168.1.3
wuuk3: 192.168.1.4

✅ 3. Create a Generic REST Command

Add this to configuration.yaml (or your split-out rest_command.yaml if you use one):

rest_command:
  wuuk_restart_streamer:
    url: "http://{{ ip }}/x/config-streamer.cgi?do=restart"
    method: get
    authentication: basic
    username: root
    password: !secret camera_password

Notes:

  • {{ ip }} is a template variable that will be provided when the service is called.
  • camera_password should be defined in your secrets.yaml.

✅ 4. Create a Script to Restart Cameras by Alias

Add this to configuration.yaml or scripts.yaml:

script:
  wuuk_restart_by_alias:
    alias: "Restart WUUK by alias"
    mode: single
    fields:
      alias:
        description: "Camera alias (e.g. wuuk1)"
        example: "wuuk1"
    sequence:
      - variables:
          ip: "{{ state_attr('sensor.camera_ip_map', alias) }}"
      - service: rest_command.wuuk_restart_streamer
        data:
          ip: "{{ ip }}"

What this script does:

  1. Receives an alias (e.g. wuuk1) as input.
  2. Looks up the IP address from sensor.camera_ip_map using that alias.
  3. Calls the REST command rest_command.wuuk_restart_streamer with the resolved IP.

You can call this script manually from the Services panel or trigger it from automations and dashboards.


✅ 5. Add Dashboard Buttons to Control Each Camera

Example Lovelace card using a grid with reboot buttons for three cameras:

type: grid
columns: 3
square: false
cards:
  - type: button
    name: Restart streamer - WUUK1
    icon: mdi:restart
    tap_action:
      action: call-service
      service: script.wuuk_restart_by_alias
      data:
        alias: wuuk1

  - type: button
    name: Restart streamer - WUUK2
    icon: mdi:restart
    tap_action:
      action: call-service
      service: script.wuuk_restart_by_alias
      data:
        alias: wuuk2

  - type: button
    name: Restart streamer - WUUK3
    icon: mdi:restart
    tap_action:
      action: call-service
      service: script.wuuk_restart_by_alias
      data:
        alias: wuuk3

Pressing a button will:

  • Call script.wuuk_restart_by_alias
  • Pass the correct alias (wuuk1, wuuk2, etc.)
  • Automatically resolve the correct IP and send the "Restart streamer" request

🧠 How It Works (Concept Overview)

Component Purpose
ip.yaml Stores alias → IP mapping
Template sensor Makes the map available inside templates
rest_command A generic command with an ip placeholder
Script Converts alias into IP and calls REST command
Lovelace buttons Trigger the script with a chosen alias

This approach:

  • Eliminates duplicated IPs
  • Simplifies maintenance
  • Keeps your Home Assistant YAML clean and organized
  • Lets you add cameras easily without touching automations/scripts

🧼 Updating or Adding Cameras

To add or update a camera, just edit ip.yaml:

wuuk4: 192.168.1.5

Once Home Assistant reloads the template entities (or after a restart), the new alias is automatically available everywhere:

  • No need to change scripts
  • No need to change automations
  • No need to modify UI buttons

Everything continues to work using the new or updated alias → IP mapping.

⚠️ **GitHub.com Fallback** ⚠️