Lollipop Camera Reverse Engineering

Lollipop Camera is designed to monitor babys. For details regarding the product, visit https://www.lollipop.camera/ website. It is quite affordable, and working pretty well.

The camera itself has a very good picture quality in night-vision or daylight. It comes with a mobile app to configure and use it.

For fun and integration, I was looking for reverse engineering, and integrate it into my existing home automation setup (OpenHAB).

RTSP Flow

First good news: the camera supports and provides a direct RTSP flow! It is however not communicated officially. I discovered it by observing network traffic with Wireshark.

Only remark is that the address of the channel is not the same for all cameras, and has a variable part in the path:

rtsp://172.16.100.181:554/live/23a711d9d154733c4c432b959db25b09/ch00_0

Good news – it was easy to reverse and understand how to get this URL part!

When the camera is associated with an account during the setup phase – it gets associated a unique identifier. If you unregister and re-pair your camera, this ID will change. The number in the path is a simple MD5 hash of this pairing ID.

To compute the MD5 hash, one can use the following command under a Unix-like system:

echo -n '<id>' | md5sum

How to obtain this ID ? 2 solutions.

First solution, use the cloud API and retrieve the list of devices associated with your account.

Second solution, use the MQTT embedded broker (see next paragraph).

Once you get this unique ID, just get the MD5 hash of it and use your favorite tool such as VLC to access the video live feed:

The video itself is standard h264 encoded, full HD (1080p) and 30fps. It also has audio (AAC).

MQTT Broker

The camera hosts an MQTT broker on typical 1883 TCP port. One remark here – it is using TLS on the 1883 port – but without any authentication (I therefore wonder the goal of using TLS if no authentication is required…).

To connect to the broker and observe the trafic, you can either use a tool such as MQTT Explorer or mosquitto_sub in CLI. Mosquitto is slightly more complex as it forces you to provide a certificate authority for TLS – even if you don’t care about validating the certificate (use of –insecure).

I recommend, if you want to go with Mosquitto, to use stunnel to remove TLS layer:

[mqtt]
client = yes
accept = 127.0.0.1:1883
connect = 172.16.100.181:1883
verifyChain = no

Then, start stunnel, and run mosquitto:

~ stunnel stunnel.conf
~ mosquitto_sub -h 127.0.0.1 -p 1883 -t '#'
{"method":"liveNote","result":{"motion":0.000000,"noise":26.137789,"ircut":1,"timestamp":1644060875}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.692110,"ircut":1,"timestamp":1644060877}}
{"method":"liveNote","result":{"motion":0.000000,"noise":26.108130,"ircut":1,"timestamp":1644060879}}
{"method":"liveNote","result":{"motion":0.000000,"noise":30.808922,"ircut":1,"timestamp":1644060881}}
{"method":"liveNote","result":{"motion":0.000000,"noise":30.426422,"ircut":1,"timestamp":1644060883}}
{"method":"liveNote","result":{"motion":0.000000,"noise":29.092848,"ircut":1,"timestamp":1644060885}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.882603,"ircut":1,"timestamp":1644060890}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.503872,"ircut":1,"timestamp":1644060892}}
{"method":"liveNote","result":{"motion":0.000000,"noise":28.854191,"ircut":1,"timestamp":1644060896}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.972601,"ircut":1,"timestamp":1644060898}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.041418,"ircut":1,"timestamp":1644060902}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.836710,"ircut":1,"timestamp":1644060904}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.788094,"ircut":1,"timestamp":1644060906}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.351727,"ircut":1,"timestamp":1644060908}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.534382,"ircut":1,"timestamp":1644060910}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.672976,"ircut":1,"timestamp":1644060912}}
{"method":"liveNote","result":{"motion":0.000000,"noise":24.879845,"ircut":1,"timestamp":1644060914}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.365896,"ircut":1,"timestamp":1644060916}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.724693,"ircut":1,"timestamp":1644060920}}
{"method":"liveNote","result":{"motion":0.000000,"noise":37.207649,"ircut":1,"timestamp":1644060922}}
{"method":"liveNote","result":{"motion":0.000000,"noise":31.941177,"ircut":1,"timestamp":1644060924}}
{"method":"liveNote","result":{"motion":0.000000,"noise":29.046495,"ircut":1,"timestamp":1644060926}}
{"method":"liveNote","result":{"motion":0.000000,"noise":25.750412,"ircut":1,"timestamp":1644060928}}

Or using a graphical tool such as MQTT Explorer:

Topics

<camera registration ID>/liveNote

{
   "method":"liveNote",
   "result":{
      "motion":0.000000,
      "noise":26.714561,
      "ircut":1,
      "timestamp":1644054668
   }
}

Messages are frequently being sent (every 3 or 4 seconds). Value can for example be used in a Grafana panel:


<camera registration ID>/cameraStatus
<camera registration ID>/cameraStatus/return
<camera registration ID>/liveNoteEnable
<camera registration ID>/liveNoteEnable/return
<camera registration ID>/watchLive
<camera registration ID>/watchLive/return
<camera registration ID>/musicStatus
<camera registration ID>/musicStatus/return
<camera registration ID>/controlMusic
<camera registration ID>/controlMusic/return
<camera registration ID>/heartbeat/return
<camera registration ID>/camSettings
<camera registration ID>/camSettings/return


<camera registration ID>/prenotify

Messages on this channel are the notifications configured, such as noisy environment:

{
   "preNotify":true,
   "event_time":1644048361346.000000,
   "camera_id":"xxxxxxxx",
   "param":{
      "camera_name":"Lollipop",
      "baby_name":"My Baby",
      "event_params":[
         {
            "event_type":3,
            "threshold":80,
            "val":80.279999
         }
      ]
   }
}

event_type:
3: noisy environment. with this event type, val is the noise level in DB.

General thoughts

I liked the fact that the camera is relatively opened, allowing the integration in existing installation. However, it is kind of insecure: getting IP connectivity to the camera, no password nor credential is required to access the video (including sound), nor control the camera through the MQTT broker.

As such, my recommendation would remain as usual: do not expose them to the internet, and if possible put all your IoT devices on a separate VLAN / SSID, with relatively strong isolation with your main network/VLAN/SSID.

Monitoring an home automation installation properly

Having home automation is great. Having it reliable and available 24/7 is even better! Especially when you use smart locks, fire sensors alarms and so on.

In this article, I’ll detail how I setup the monitoring of my Home Automation infrastructure using Zabbix. The perfect monitoring is a mix of detection and also alerting.

First of all – you need to identify what are your different components, and what do you want to monitor ? Which layers ?

Bottom-up – it starts with the hardware:

  • Switches
  • Routers
  • Servers
  • Appliances
  • Gateways (KNX-IP…)

Next, system:

  • Virtual Machines
    • Operating System
  • Containers (Docker)

Software:

  • openHAB

Components:

  • openHAB binding states

To begin with, I decided to startup with a “Dockerized” Zabbix environment. My stack is very simple:

---
version: "2"
networks:
  zabbix-internal:
    driver: bridge
  web:
    external:
      name: web
services:
  zabbix-mysql:
    image: mysql
    container_name: zabbix-mysql
    networks:
      zabbix-internal:
    environment:
      MYSQL_ROOT_PASSWORD: *********
    volumes:
      - "/srv/iscsi/dockers/zabbix/mysql:/var/lib/mysql"
    restart: unless-stopped
    labels:
      - "traefik.enable=false"
  zabbix-server:
    # Documentation: https://hub.docker.com/r/zabbix/zabbix-server-mysql
    image: zabbix/zabbix-server-mysql
    container_name: zabbix-server
    restart: unless-stopped
    networks:
      zabbix-internal:
    ports:
      - "10051:10051"
    environment:
      TZ: "Europe/Paris"
      DB_SERVER_HOST: "zabbix-mysql"
      MYSQL_USER: "root"
      MYSQL_PASSWORD: "**********"
      ZBX_STARTPINGERS: 5
      ZBX_JAVAGATEWAY: "zabbix-java-gateway"
      ZBX_JAVAGATEWAYPORT: 10052
      ZBX_JAVAGATEWAY_ENABLE: "true"
      ZBX_STARTJAVAPOLLERS: 5
    labels:
      - "traefik.enable=false"
  zabbix-java-gateway:
    image: zabbix/zabbix-java-gateway
    container_name: zabbix-java-gateway
    restart: unless-stopped
    networks:
      zabbix-internal:
    environment:
      TZ: "Europe/Paris"
    labels:
      - "traefik.enable=false"
  zabbix-frontend:
    image: zabbix/zabbix-web-nginx-mysql
    container_name: zabbix-frontend
    restart: unless-stopped
    networks:
      zabbix-internal:
      web:
    environment:
      TZ: "Europe/Paris"
      PHP_TZ: "Europe/Paris"
      DB_SERVER_HOST: "zabbix-mysql"
      MYSQL_USER: "zabbix-frontend"
      MYSQL_PASSWORD: "*****************"
      ZBX_SERVER_HOST: "zabbix-server"
      ZBX_SERVER_NAME: "Ben"
  

You’ll notice that in addition to a “basic” Zabbix stack, I added Zabbix Java Gateway, to be able to monitor openHAB JVM properly.

The monitoring of hardware is pretty easy and standard: SNMP, or even better, Zabbix Agent ! Most hardware support SNMP (I mean – decent hardware), and most operating system, whatever architecture, avec Zabbix agent packaged in standard package manager they come with. Devices that I monitor using SNMP & Zabbix agents:

  • Router (Ubiquiti EdgeRouter)
  • Switches (Ubiquiti EdgeSwitch)
  • Wireless Access Points (Ubiquiti Unifi NanoHD, InWall HD)
  • Linux hosts (VM and physical – including Raspberry, OrangePi…)
  • ESXi hypervisor
  • Synology NAS (storage + CCTV)

There are devices that you want to monitor but unfortunately don’t provide SNMP. This is for example the case of Apple TV, Sonos devices, and Tasmota devices, which I widely use for their cost and efficiency in my installation. For those device, you have multiple choice:

  • monitor that they are alive using traditional ICMP ping
  • monitor that the services are up (HTTP for example)

I found that ICMP was sufficient for Apple TV, Sonos and Tasmota devices.

Your monitoring should be driven by your “threats”: what are you scared about ?

In my case, I am scared of being locked down out of my apartment. So I need to be sure that openHAB is working well (Java app -> monitor the JVM), ensure that openHAB is well connected to the various bridges/gateways (bindings), and also ensures that some devices are still reporting alive (zigbee battery devices).

I will not detail the basic steps of creating a HOST and configuring a Zabbix environment, Google is full of that ! I will only focus on specific aspects of openHAB.

We will be using the openHAB REST API to monitor the inside of openHAB and bindings:


Then:

Once you have created your item within a host, just create a trigger:

Integrating Daikin Madoka (BRC1H) in openHAB

Daikin Madoka, also known as BRC1H, are new generation of home air-conditioning wired thermostat, that also allow control from mobile phone through Daikin “Madoka Assistant” application.

I got 3 Madoka thermostat installed in my new flat and having them connected to the rest of my Home Automation infrastructure was not optional!

Several options :

  • Buy a Daikin KNX gateway (3 necessary – one on each internal unit)
  • Develop a component that could take benefit of BRC1H/Madoka thermostats.

The KNX gateways are expensive (~300€ / unit), and not sure about their good integration/availability – could find very limited information on it – and as I’m still a geek with some technical skills, I decided to go with option #2 – develop a component interacting with Madoka thermostats!

The reverse engineering of the protocol used by the mobile app and the Madoka thermostat can be found on my github: https://github.com/blafois/Daikin-Madoka-BRC1H-BLE-Reverse

In a future article, I’ll detail the steps to setup a BLE Peripheral and BLE Central using Bleno and Noble (JS).