User Tools

Site Tools


doc:appunti:hardware:iot

This is an old revision of the document!


IoT - Internet of Things

Teckin Smart Plug SP22

Di queste prese intelligenti marchiate Teckin ne esistono almeno due versioni. Le più vecchie si basano sul chip ESP mentre quelle più recenti si basano sul chip Realtek RTL8710BN. Questo fa molta differenza se si vuole cambiare il firmware originale con quello libero ed open source Tasmota, infatti Tasmota è compatibile solo con il chip ESP.

Le prese - con la configurazione originale - utilizzano la piattaforma cloud Tuya per essere controllate. Esiste l'app Smart Life - Smart Living per Android ed una equivalente per iOS.

Perché il Cloud Tuya è male

Abbiamo provato a gestire una presa intelligente Teckin SP22 tramite le API della libreria Python TinyTuya. Per quanto mi riguarda l'esperienza è del tutto disastrosa in termini di flessibilità e libertà di programmazione. Questo un riassunto delle motivazioni.

Per poter gestire un device Tuya tramite API è necessario:

  • Installare la app Smart Life (Android o iOS) e fare il pairing del device sulla app.
  • Attivare un account developer sul cloud Tuya (gratuito solo in prova limitata nel tempo).
  • Aggiungere il device sul Cloud Tuya.
  • Se si decide di spostare il device su una diversa rete (cambio dell'ESSID WiFi) è necessario ripetere l'operazione di pairing che dipende dal cloud Tuya. Questa operazione modifica la local key del dispositivo (utilizzata dalla API TinyTuya) ed è necessario ottenerne una nuova dal cloud Tuya.
  • Un dispositivo, quando viene acceso, chiama il cloud Tuya per determinare eventuali variazione al suo stato corrente (ad esempio lo stato ON/OFF dello switch). Se il cloud non è raggiungibile (ad esempio per mancanza di connettività), il dispositivo resta in uno stato indefinito in cui non può essere controllato dalla API TinyTuya. È necessario premere almeno una volta il pulsante per cambiare il suo stato per poterlo comandare nuovamente via API.
  • Appena si rimuove una device dalla app, il Cloud invia al device stesso l'istruzione di reset. Il dispositivo resetta tutta la sua configurazione ed entra immediatamente in pairing mode. Se il device non è on-line al momento della sua rimozione dalla app, l'istruzione di reset viene comunque inviata appena esso torna on-line.

Smart Life App

The QR code printed on the plug itseld points to http://e.tuya.com/smartlife, here you can download the 76.7 Mb smartlife.apk. We prefered to download it from the Google Play, searching the Smart Life - Smart Living app by Volcano Technology Limited, at the URL https://play.google.com/store/apps/details?id=com.tuya.smartlife. Strangely enough, the Google Play app is only 40.35 Mb…

Pairing the smart plug with the App and WiFi

  1. Plug the SP22 into an electricity outlet.
  2. Start the Smart Life app on the smartphone (it shows a warning message if the phone is rooted).
  3. Tap Try now (Provalo adesso) to use the app without registering an account.
  4. Tap the + in the upper-right corner Add devices (Aggiungi dispositivo).
  5. Select the Electrical Outlet Wi-Fi (Presa Wi-Fi).
    • If you negate the localization permission, you will be required to manyally enter the WiFi network name.
    • Input the ESSID and password.
  6. Press the button on the SP22 for 5 seconds: the LED under the button start flashing in blue, about three time per second: the device is in pairing mode.
  7. Tap the Next button into the app as required, untill the app start searching for the device.
  8. The procedure on the smartphone should terminate with the message Successfully Added (Aggiunto con successo).

After the pairing

  • The SP22 connect to the WiFi network, getting an IP address from the local DHCP server. You can view the request into the DHCP server log, coming from a Tuya Smart Inc. MAC address (prefix d4:a6:51). In my case the device presented itself with the name TY_WR.
  • The device has the port 6668/TCP open.
  • The device broadcasts on the local network using port 6667/UDP.
  • The device communicates with several internet servers on port 8886/TCP. In our case it was an Amazon AWS under the DNS name m2.tuyaeu.com or a3.tuyaeu.com (they resolve into several and changing IP addresses).
  • The SP22 can be switched on/off from the smartphone.

How the app communicates witht the device

  • If the Smart Plug has internet connectivity, it gets commands from the cloud server.
  • If the Smart Plug does not have internet connectivty, it gets commands from the LAN.
  • The smartphone detects if it can use internet or LAN connectivity to communicate with the device. If bot connections are broken, the device appears as “off-line” into the app.
  • With default configuration, the SP22 remembers its last status (on or off) when it recovers from a power failure.

How the app communicates witht the cloud

  • It seems that the app does not make DNS calls to resolve for the cloud server name, at least in my case I cannot detect any DNS requests, even after a smartphone reboot. The app communicates on port TCP/8883 (Secure MQTT) with an Amazon AWS server,IP address 18.194.10.142.

How to create a Tuya Developer Account

To use the TinyTuya library we need the device local key. This key is assigned by the Tuya Cloud to your device when you do the pairing with the Smart Life app. The key will be valid and can be used locally to control your device even if the Tuya cloud is unavailable, but you cannot move the device into another network; in that case you need to obtain a new local key from Tuya cloud.

Actually we need to:

  • Register an account at https://iot.tuya.com/.
  • Open a support ticket asking to be upgraded to developer. If you are not enabled and you try to create a cloud project, you get an error like this: Your account is not yet available for cloud development platform. The cloud development platform can only be used after completing personal authentication or enterprise authentication).
  • Create a Cloud Project.
  • Link the devices you have enabled into the Smart Life app into the Cloud Project.
  • Authorize the use of the API for this Cloid Project.

These are the steps to be executed into the Web Framework:

  • Cloud
    • Projects
      • Try It Free
        • Project Name: TinyTuya Python API
        • Description: Manage Tuya devices from GNU/Linux
        • Industry: Other
          • Authorization Key
            • Access ID/Client ID: 4e46be08d231a017dc2c
            • Access Secret/Client Secret: 0061ee191a3e90e22467c1be8dce4b1f
            • Any IP can use the authorized key to access the API of this project
    • Link Devices
      • Select the Project TinyTuya Python API from drop-donw menu
        • Link devices by App Account ⇒ Add App Account (a QR-code appear)
        • Start the Smart Life app on the smartphone ⇒ Me
          • Tap the top-right icon [-] and scan the QR-code
    • API Groups
      • Select the Project TinyTuya Python API from drop-donw menu
        • Authorization management: Open (Reason: TinyTuya requests)
        • Device Management: Open
        • Device Control: Open

TinyTuya Python library

Il nostro obiettivo è poter controllare i dispositivi tramite una qualche API, possibilmente in Python e con esigenze modeste. La piattaforma di riferimento è Raspberry Pi o una qualunque distribuzione GNU/Linux.

La scelta è caduta sulla libreria Python TinyTuya, che sembra rispondere a tutte le richieste. L'installazione ha dei prerequisiti che possono essere soddisfatti con l'installazione locale via pip, qualora la distribuzione di riferimento non li soddisfi. In particolare la libreria python3-crypto offerta da Debian 10 è adeguata, mentre la libreria python3-pycryptodome di Debian è alla versione 3.6.1, mentre TinyTuya richiede 3.9.9. In definitiva si possono scaricare i pacchetti dal repository https://pypi.org/ e installarli manualmente:

pip3 install pycryptodome-3.9.9-cp37-cp37m-manylinux1_x86_64.whl
pip3 install tinytuya-1.1.2-py2.py3-none-any.whl

Scanning for devices on the LAN

After installing the TinyTuya Python library, just run:

python3 -m tinytuya

TinyTuya (Tuya device scanner) [1.1.2]

Scanning on UDP ports 6666 and 6667 for devices (15 retries)...

3.3 Device Found [Valid payload]: 10.0.0.129
    ID = bff7e612edf4edb899uaiz, Product ID = keyqwtgrcsf3hxng, Version = 3.3
    No Stats - Device Key required to poll for status

Scan Complete!  Found 1 devices.

According to the instruction of the TinyTuya Readme, we need the following data to interact with the device:

DEVICE_ID This is the device ID shown after the devices scan performed by python3 -m tinytuya.
IP_ADDRESS This is the IP address acquired by the device, this is shown by python3 -m tinytuya.
LOCAL_KEY This is a API programming key obtained from the Tuya Cloud. You need to register to the Tuya web developmente framework and obtain a developer account. It seems that this requires a payment, but a free trial period exists.

Let's see how to obtain a Tuya Developer account on https://iot.tuya.com. As I reported into the issue #15 it seems that a Developer Account is not longer available for free, nor it is so simple to obtain.

Getting the device local key and programming

Now we use TinyTuya library to get the local key required to control the device. NOTICE: run the tinytuya wizard in a terminal with a dark background, otherwise you cannot read the white text!

python3 -m tinytuya wizard

Enter API Key from tuya.com: 4e46be08d231a017dc2c
Enter API Secret from tuya.com: 0061ee191a3e90e22467c1be8dce4b1f
Enter any Device ID currently registered in Tuya App (used to pull full list): bff7e612edf4edb899uaiz
Enter Your Region (Options: us, eu, cn or in): eu

Some output will be displayed on the screen and two files are created: tinytuya.json and devices.json

{
    "apiKey": "4e46be08d231a017dc2c",
    "apiSecret": "0061ee191a3e90e22467c1be8dce4b1f",
    "apiRegion": "eu",
    "apiDeviceID": "bff7e612edf4edb899uaiz"
}
[
    {
        "name": "Presa #1",
        "id": "bff7e612edf4edb899uaiz",
        "key": "a28b367332e8b5ee"
    }
]

Finally you can control the device using Python. Here it is an example on how to get the status of the smart switch and toggle its status:

#!/usr/bin/env python3
import tinytuya
d = tinytuya.OutletDevice('bff7e612edf4edb899uaiz', '10.0.0.129', 'a28b367332e8b5ee')
d.set_version(3.3)
data = d.status()  
# Show status and state of first controlled switch on device
print('Dictionary %r' % data)
print('State (bool, true is ON) %r' % data['dps']['1'])
# Toggle switch state
switch_state = data['dps']['1']
data = d.set_status(not switch_state)
if data:
    print('set_status() result %r' % data)

Here it is an example of the dictionary returned by the tinytuya.OutletDevice().status() method. There are several keys, where the 1 is the ON/OFF status and the 20 is the voltage in decivolt:

Dictionary {'dps': {'1': True, '9': 0, '18': 0, '19': 0, '20': 2302}}
State (bool, true is ON) True

Tasmota and Tuya-Convert

La soluzione Tuya Cloud è ovviamente non accettabile se si vuole avere il controllo dei device al di fuori del circolo vizioso Smart Life app - Tuya Cloud. Purtroppo sostituire il firmware originale con Tasmota pare che sia diventato impossibile. Anzitutto sembra che Teckin si sia impegnata a rendere impossibile il funzionamento di Tuya-Convert (tool per il flash del firmware Tasmota), almeno a giudicare dalla issue 197. Poi, cosa ancora più grave, sembra proprio che le nuove versioni di SP22 siano basate su chip Realtek non compatibile con Tasmota, vedere questa pagina informativa.

Sonoff Basic R2

Il vantaggio di quesi power switch intelligenti marchiati Sonoff, è che sono facilmente programmabili con il firmware Tasmota. Tasmota è un progetto free ed open source che consente di realizzare la propria infrastruttura IoT totalmente indipendente da qualunque architettura cloud di terze parti. In pratica è possibile gestire i dispositivi basati sul chip ESP8266 utilizzando protocolli aperti (MQTT) e creando il proprio server cloud, ad esempio con il broker MQTT mosquitto, ed utilizzando i più vari MQTT client, come ad esempio Home Assistant.

Sonoff Basic R2: Opening the case

To open the plastic case of the Sonoff Basic R2 you have to unlock the four snap fit joints: there are two on each of the long edges.

Sonoff Basic R2: Components Sonoff Basic R2: PCB

Sonoff Basic: RF R2 Power V1.3 Sonoff Basic R2: ESP8285 chip and antenna

Tools required to flash the Tasmota firmware

  1. Pin headers to be soldered on the Sonoff Basic PCB.
  2. An USB to serial adapter.
  3. The esptool.py flashing tool (Python program).
  4. The tasmota.bin firmware to be uploaded (flashed) into the Sonoff Basic.

You can download the esptool.py form the esptool GitHub repository, I used version 3.0. You can install it or just extract the archive and run it from the extract directory.

The Tasmota firmware can be downloaded from the Tasmota GitHub repository, I used the tasmota.bin version 9.2.0 found into the download page.

Flashing the Tasmota firmware

To flash the Tasmota firmware I used a GNU/Linux computer and an USB to serial adapter based on the CP210x chip. With the help of a multimeter I verified that the adapter provides the 3.3 Volt power on the proper pin: this current is used to power the Sonoff device during the flash.

  1. Disconnect the Sonoff Basic from AC power.
  2. Connect the USB to serial adapter to the Sonoff serial, all the 4 wires are required: 3.3 Volt, TX, RX and GND. The TX line of the adapter is connected to the RX line of Sonoff, and vice-versa.
  3. Execute each step of the flashing procedure in this manner:
    • Connect the USB adapter to the computer while holding down the push button of the Sonoff device. Keeping the button pressed for 7 seconds is sufficient. Keeping the button pressed while power-on is required to put the device into a special programming mode.
    • Execute the required esptool.py command on the PC.
    • Disconnect the USB adapter from the PC.

This is the concise list of commands I used (remember: each command is executed after the Sonoff device is booted in programming mode as explained above!):

./esptool.py --port /dev/ttyUSB0 flash_id
./esptool.py --port /dev/ttyUSB0 read_flash 0x00000 0x100000 sonoff-r2-1mb.orig.bin
./esptool.py --port /dev/ttyUSB0 erase_flash
./esptool.py --port /dev/ttyUSB0 write_flash -fs 1MB -fm dout 0x0 tasmota.bin

Running the command ./esptool.py -h you get the explanation of each command, this is a summary of what I used:

flash_id Read SPI flash manufacturer and device ID
read_flash Read SPI flash content
erase_flash Perform Chip Erase on SPI flash
write_flash Write a binary blob to flash

Here it is the output generated by the write_flash command:

./esptool.py --port /dev/ttyUSB0 write_flash -fs 1MB -fm dout 0x0 tasmota.bin
esptool.py v3.0
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8285
Features: WiFi, Embedded Flash
Crystal is 26MHz
MAC: c8:2b:96:ee:b8:3c
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 600960 bytes to 428969...
Wrote 600960 bytes (428969 compressed) at 0x00000000 in 37.9 seconds (effective 127.0 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...

After the write_flash command you can power-cycle the Sonoff device by unplugging and plugging the USB adapter again, this time without holding the Sonoff button. The LED on the Sonoff flashes in blue, the device starts into Access Point mode and stays this way for about three minutes, connect a smartphone or the notebook to it (search for an ESSID like tasmota-xxxx) and browse the address http://192.168.1.4/. Here you have to configure the WiFi parameters to let the Sonoff Basic connect to your WiFi network; you can specify two different ESSID, that the Tasmota firmware will search to connect to.

NOTICE :!: I had some problems connecting to the Sonoff Access Point using the smartphone and using the notebook: sometimes the IP address were not assigned, other times the host 192.168.4.1 were not reachable. One time I succeded by setting the IP address manually (in the range 192.168.4.x), another time I succeded by enabling the WiFi option Allow lower bitrates (GNU/Linux Wicd Network Manager).

AP1 SSId/Password ESSID and password of the first Access Point
AP2 SSId/Password ESSID and password of the second Access Point
Hostname The name used when registering to the DHCP server. Defaults to %s-%04d which means the name you will configure into MQTT topic (see below), followed by a four digits decimal number. The number is derived from the 13 least significant bits of the MAC address.
CORS Domain If empty (default) Tasmota allows HTTP requests only from the connecting client. You can specify an asterisk to allow the sharing of resources with any domains, or you can specify just one URL (e.g. http://host.domain.tld) which will be the only one domain allowed to share Tasmota HTTP resources.

Hardware Module Configuration

After WiFi configuration, you can reboot the Tasmota device, wait unitll it gets an address from your WiFi Access Point and complete the configuration; you have to tell to the Tasmota firmware what hardware it can control.

  • Configure the device name and template. Choose a name to identify this device and select the appropriate template. The template tells the firmware how to use the hardware (the relay and the LED): just use the default Sonoff Basic (1).
    • ConfigurationConfigure TemplateBased onSonoff Basic (1)
  • Protect the web access with a password (beware that it uses plain http, so password can be sniffed along the network):
    • ConfigurationConfigure OtherWeb Admin Password
  • Disable the Access Point mode if WiFi AP is missing. If the device is unable to connect to the two configured WiFi networks, it enters automatically into the WifiConfig Access Point mode, allowing a WiFi client to connect and make configuration (this is the WifiConfig mode 2). This is can be a security threat if you have not set the web access password. You can go further in securing the device by changing the WifiConfig mode:
    • Connecto to the web interface, Main MenuConsole and enter the command WifiConfig 5. This means wait until selected AP is available again without rebooting. Beware that the 6 short presses of the button (see below) will revert to WifiConfig 2.

Button Reset

If you have trouble connecting to a Tasmota device and the device have a button, you have at least two methods to try to recover.

6 short presses Press the button six times very quickly (be rapid enough to prevent the relay switch to toggle). Tasmota changes to WifiConfig 2 mode, i.e. it starts the Wi-Fi Manager Access Point (with web server at 192.168.4.1) for 3 minutes, then reboot. This button behaviour can be disabled using SetOption1 1. The WifiConfig mode 2 remains permanent unless you reconfigure it, this means that if the device is unable to find one of the two Access Points it knowns, it switches into the Access Point mode allowing WiFi clients to connect.
Long press for 40 seconds Tasmota will reset to firmware defaults and restart.

Controlling Tasmota via MQTT

MQTT is a client/server protocol, it allows a client to send messages to other clients which are subscribed to a common topic. The server acts as a broker for this publish/subscribe mechanism.

WARNING: Commands over MQTT are sent in clear-text, including passwords. You must trust your network against traffic sniffing! Using TLS in Tasmota is disabled by default, because it requires too much memory; see the page TLS Secured MQTT.

Installing a MQTT Broker

On a GNU/Linux Debian host (version 10 Buster) I installed the following packages:

  • mosquitto
  • mosquitto-clients

The daemon mosquitto is running and listening on port TCP/1883. The traffic on this port is unencrypted so although passwords are usually used, beware when you open the firewall, etc.

With default configuration, the mosquitto broker is open to everyone, just try to subscribe to a topic and - from another terminal - publish something on the same topic:

mosquitto_sub -h mqtt.server.tld -t my_topic
mosquitto_pub -h mqtt.server.tld -t my_topic -m "Hello, world!"

On the first terminal you will get the message Hello, world!.

Configuring MQTT on Tasmota

From the Tasmota Main menuConfigurationConfigure MQTT:

Host Hostname or IP address of the MQTT server.
Port Default is 1883, which is MQTT TCP unencrypted.
Client Default is DVES_%06X, where %06X means the last 3 bytes of MAC address, in hex.
User Username for authenticating on the MQTT broker, default is DVES_USER.
Password Password for authenticating on the MQTT broker.
Topic Default is tasmota_%06X, where %06X means the last 3 bytes of MAC address, in hex.
Full Topic Default is %prefix%/%topic%/

From the Tasmota Main menuConfigurationConfigure other:

MQTT enable Checkbox to enable the service.
Device Name Default is Tasmota.
Friendly Name 1 Used by the autodiscovery feature, default is Tasmota.

Here it is an example to publish an MQTT message asking the Sonoff device to toggle the switch:

mosquitto_pub -h mqtt.server.tld  -t 'cmnd/tasmota_EEB73A/Power' -m 'TOGGLE'

NOTICE: If you use a non-existent topic (e.g. a wrong device name), no error is reported.

Obviously the device understands the TOGGLE, ON and OFF messages. If you are subscribed to the proper MQTT topic, you will receive a message for each toggle:

mosquitto_sub -h mqtt.server.tld -t "stat/tasmota_EEB73A/RESULT"
{"POWER":"OFF"}
{"POWER":"ON"}

Password protect the Mosquitto broker

Default Debian installation of the mosquitto server does not require a password from the connecting client.

/etc/mosquitto/acls

user username1
topic write gateway/+/event/+
topic read gateway/+/command/+

user username2
topic readwrite gateway/+/event/+

/etc/mosquitto/conf.d/auth.conf

allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acls

To manage a password file you can use the mosquitto_passwd tool, this command will set an username with a passowrd (asked interactively) into the password file (add a -c option to create the password file):

mosquitto_passwd /etc/mosquitto/passwd username

The file contains sha512 hashes; to avoid world-read you can change the file mode to 0640. The file is read at program start using root privileges; if the file is changed the mosquitto server must be restarted.

Now you have to specify the correct username and password when you execute mosquitto_pub, otherwise the command will fail:

mosquitto_pub -h mqtt.server.tld -u 'username' -P 'WrongPassword' -t 'cmnd/smart-cable/Power' -m 'TOGGLE'
Connection Refused: not authorised.
Error: The connection was refused.

Controlling Tasmota via HTTP GET

The Tasmota firmware exposes an open, admin mode, web interface to configure and control the device status (this default can be changed). It is advisable to set a password from Main menuConfigurationConfigure OtherWeb Admin Password. The default username is admin.

WARNING: Commands over HTTP are sent in clear-text, including passwords. You must trust your network against traffic sniffing!

Suppose that your Tasmota device has IP address 10.0.0.114, username admin and password MySecret, you can remotely control it on the command line using GET commands, e.g. using wget:

# Control the relay status: Toggle, switch it On, switch it Off.
wget -q -O /dev/null 'http://10.0.0.114/cm?user=admin&password=MySecret&cmnd=Power%20Toggle'
wget -q -O /dev/null 'http://10.0.0.114/cm?user=admin&password=MySecret&cmnd=Power%20On'
wget -q -O /dev/null 'http://10.0.0.114/cm?user=admin&password=MySecret&cmnd=Power%20Off'

If you want to read the relay status after the command, read the output of the GET request (a JSON string):

wget -q -O - 'http://10.0.0.114/cm?user=admin&password=MySecret&cmnd=Power'
{"POWER":"ON"}

Web References

doc/appunti/hardware/iot.1611142857.txt.gz · Last modified: 2021/01/20 12:40 by niccolo