Hacking TechLife Pro bulbs

Hello.

I just bought some china smartlights from aliexpress that i hoped i was able to flash tasmota firmware. But it seems like TechLife Pro is another app, and not based on tuya cloud.
The bulbs are available from here: Amtoo bulb

Anyway, i installed the app and paired up the bulbs and started tcpdump on my router to find out how this worked. It turnes out that its using mqtt, and the bulbs subscribe to a topic on their server.
After some research and alittle help from a friend, we figured out that they connect to an mqtt server.

Here is a dump of the traffic: https://i.imgur.com/oKrHwtx.png

The dump shows that i did the following events:

  • Turn light off
  • Turn light on
  • dim to minum
  • dim up about 20% ( implemented as a slider)
  • dim up
  • dim up
  • dum up
  • lights off
  • lights on

Here is a hex dump of the events separated with red: https://imgur.com/87XiPhz

Anyway, i redirected the dns to their cloud to my own mqtt. And here you go, the bulb connects just fine. And i can send on and off to it with:

Blockquote
echo -en “\xfa\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\xfb” | mosquitto_pub -t ‘dev_sub_2e:71:3c:6d:3f:bb’ -s
echo -en “\xfa\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\xfb” | mosquitto_pub -t ‘dev_sub_2e:71:3c:6d:3f:bb’ -s

Works very well and fast. But now i want to figure out how the dimming works. I can ofc hardcode 4-5 different states, but i really wanted to be able to controll from 0-100%. But i cannot figure it out.
I found this document but it dosent seem to be the same protocoll.

Any tips?

1 Like

Thanks for this, I am interested in trying to debug these bulbs too.

I am having some trouble being able to get started debugging the messages. When I tried a tcpdump on my wireless network I was not able to observe the messages you are seeing. Do you have any tips to get started?

For reference I purchased these bulbs: https://www.aliexpress.com/item/4000124863580.html?spm=a2g0s.9042311.0.0.4a4f4c4dKNYy5C

i ran the tcpdump on my router. Saved the files if you want to take a look at them?

But i was thinking i should get some more samples, so i can “hardcode” dimming in steps of 10. For instance this is the lowest lightsetting:
echo -en “\x28\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x01\xf0\x95\x29” | mosquitto_pub -t ‘dev_sub_xx:xx:xx:xx:xx:xx’ -s

And the highest:
echo -en “\x28\x00\x00\x00\x00\x00\x00\x11\x27\x00\x00\x00\x64\xf0\xa2\x29” | mosquitto_pub -t ‘dev_sub_xx:xx:xx:xx:xx:xx’ -s

You can probably send that to their mqtt server if you dont want to run your own

Little update. I found some more codes to use.

  • 10 % -echo -en “\x28\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x01\xf0\x95\x29”
  • 25 % - echo -en “\x28\x00\x00\x00\x00\x00\x00\x36\x04\x00\x00\x00\x0a\xf0\xc8\x29”
  • 50 % - echo -en “\x28\x00\x00\x00\x00\x00\x00\x23\x0e\x00\x00\x00\x24\xf0\xf9\x29”
  • 75% - echo -en “\x28\x00\x00\x00\x00\x00\x00\x89\x14\x00\x00\x00\x34\xf0\x59\x29”
  • 100% - echo -en “\x28\x00\x00\x00\x00\x00\x00\x11\x27\x00\x00\x00\x64\xf0\xa2\x29”

So i decided to try to integrate this in openhab using a switch and a dimmer.

Itemfile as follows:

// Kina lysene fra ali

Group gKinaKontorLys				"Kinalys1"				<light>			(gKontor, gItems)
Switch kinaKontorLys				"Kinalys1 switch"		<light>			(gKinaKontorLys)
Dimmer kinaKontorDimmer				"Kina1Dimmer"							(gKinaKontorLys)

And i had to make a script to controll them + and rules file.

// kinalys 1 på kontor.

rule "kinalys1 switch on"
when Item kinaKontorLys changed to ON
then
	logInfo("kina", "kinalys1 til på")
	executeCommandLine("/etc/openhab2/misc/kinalys/lys1.sh on",10000)
end

rule "kinalys1 switch off"
when Item kinaKontorLys changed to OFF
then
        logInfo("kina", "kinalys1 til av")
        executeCommandLine("/etc/openhab2/misc/kinalys/lys1.sh off",10000)
end

rule "Kinalys1 dimmer mottatt"
when Item kinaKontorDimmer received update
then
	logInfo("kina", "kinalys fikk " + kinaKontorDimmer.state )
	executeCommandLine("/etc/openhab2/misc/kinalys/lys1.sh dim " + kinaKontorDimmer.state,10000)
end

And a little bashscript:

#!/bin/bash

t="dev_sub_xx:xx:xx:xx:xx:xx"

if [ "$1" != "" ]; then



	if [ "$1" == "on" ]; then
		echo -en "\xfa\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\xfb" | mosquitto_pub -t $t -s	

	elif [ "$1" == "off" ]; then
		echo -en "\xfa\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\xfb" | mosquitto_pub -t $t -s

	elif [ "$1" == "dim" ]; then
			if ((1<=$2 && $2<=10))
			then
				echo -en "\x28\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x01\xf0\x95\x29" | mosquitto_pub -t $t -s
			elif ((11<=$2 && $2<=25))
			then
				echo -en "\x28\x00\x00\x00\x00\x00\x00\x36\x04\x00\x00\x00\x0a\xf0\xc8\x29" | mosquitto_pub -t $t -s
			elif ((26<=$2 && $2<=50))
			then
				echo -en "\x28\x00\x00\x00\x00\x00\x00\x23\x0e\x00\x00\x00\x24\xf0\xf9\x29" | mosquitto_pub -t $t -s
			elif ((51<=$2 && $2<=75))
			then
				echo -en "\x28\x00\x00\x00\x00\x00\x00\x89\x14\x00\x00\x00\x34\xf0\x59\x29" | mosquitto_pub -t $t -s
			elif ((76<=$2 && $2<=100))
			then
				echo -en "\x28\x00\x00\x00\x00\x00\x00\x11\x27\x00\x00\x00\x64\xf0\xa2\x29" | mosquitto_pub -t $t -s
			fi
	fi
else

echo "Usage: "
echo "$0 on - turn on"
echo "$0 off - turn off"
echo "$0 dim % - dimmer"

fi

Alittle hackish, but it works like a charm. Note that its one way, so if something else (ie you run the script at the commandline), they wont be in sync.
But for me, who uses openhab to automaticly controll the lights this is working as intended.
And its very fast aswell!

1 Like

I go a little deeper into the protocol and found how to control the level of brigtness more accurately.

Brightness level is unsigned short from 0 to 10000. Write it to 7 and 8 bytes in little endian format.
14th byte is checksum. For calculating just XOR all bytes from 1 to 13.

Same info in table view:

byte value
0 Command type. Use \x28 for change brightness
1 0
2 0
3 0
4 0
5 0
6 0
7 Second byte of brightness level (little endian).
8 First byte of brightness level (little endian)
9 0
10 0
11 0
12 0
13 \F0
14 XOR of all bytes from 1 to 13.
15 \x29

C++ sample:

void setBrightnessLevel(int Level)
{
    unsigned char MqttCommand[] = "\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x29";

    MqttCommand[7] = (Level & 255);
    MqttCommand[8] = ((Level >> 8) & 255);

    unsigned char Checksum = 0;
    for (int byteNum = 1; byteNum < 14; byteNum++)
    {
        Checksum ^= MqttCommand[byteNum];
    }
    MqttCommand[14] = (Checksum & 255);

    ...
1 Like

Dear very good work!
I have one question about this hack process. How I redirected the dns to their cloud to my own mqtt? Any help about this

Freaking sweet! Im going to try to make something from this. Really helpful, thanks alot for sharing.

Well you need to tell your dnsserver to redirect that. Or override. it really depends on your setup. But basicly you need a caching nameserver or your own nameserver.

This is really impossible with ASUS RT-N18U, Windows and end users.
I want method which connect with smart bulb and replace his DNS server name in chip as that resolve TechLife Pro app.
This change must be trough AP-TechLife-??:??.
You know about this possibility?

This is really impossible with ASUS RT-N18U, Windows and end users.
I want method which connect with smart bulb and replace his DNS server name in chip as that resolve TechLife Pro app.
This change must be trough AP-TechLife-??:??.
You know about this possibility?

Im not sure about that router. I found this: https://github.com/RMerl/asuswrt-merlin/wiki/Custom-domains-with-dnsmasq

But if you can specify static ips in the dhcp server, i guess you can redirect it somewhere else? Ie your “fake” dns server.
I run pfsense, so it was no problem for me.

1 Like

Small update. Since i dont want to implement all this logic in openhab, i have created it outside of openhab. After i got the code from Yaros i updated the bash script and created a c++ (very horrid) code.

Here is the new bash script:

 #!/bin/bash

t="dev_sub_xx:xx:xx:xx:xx:bx"

if [ "$1" != "" ]; then



	if [ "$1" == "on" ]; then
		echo -en "\xfa\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\xfb" | mosquitto_pub -t $t -s	

	elif [ "$1" == "off" ]; then
		echo -en "\xfa\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\xfb" | mosquitto_pub -t $t -s

	elif [ "$1" == "dim" ]; then
		# Gang opp med 100.
		d=$(expr $2 \* 100)
		k=$(/etc/openhab2/misc/kinalys/ckinalys $d) ; echo -en $k | mosquitto_pub -t $t -s
		

	fi
else

echo "Usage: "
echo "$0 on - turn on"
echo "$0 off - turn off"
echo "$0 dim % - dimmer"

fi

the ckinalys code looks like this:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sstream>

using namespace std;

void setBrightnessLevel(int Level) {
//cout << "Debug: " << Level << "\n";
unsigned char MqttCommand[] = "\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x29";
MqttCommand[7] = (Level & 255);
MqttCommand[8] = ((Level >> 8) & 255);
  unsigned char Checksum = 0;
    for (int byteNum = 1; byteNum < 14; byteNum++)
    {
        Checksum ^= MqttCommand[byteNum];
    }
    MqttCommand[14] = (Checksum & 255);

	char ut[512] = ""; // tom til å begynne med
	for (int i = 0; i != 16; i++) {
		char tmp[8];
		sprintf(tmp, "\\x%02x", MqttCommand[i]);
		strcat(ut, tmp);
		}
	printf("%s", ut);
}

int main(int argc, char** argv) { 
if (argc == 2) {
    std::istringstream ss(argv[1]);
int x;
if (!(ss >> x)) {
  std::cerr << "Invalid number: " << argv[1] << '\n';
  return 1;
} else if (!ss.eof()) {
  std::cerr << "Trailing characters after number: " << argv[1] << '\n';
}
    setBrightnessLevel(x);
    }
else {
cout << "Usage: " << "\n";
cout << argv[0] << " dimlevel (int)" << "\n";
}
return 0;
} 

its compiled with g++ main.cpp -o ckinalys
Now the slider actually works from 1 to 100%

Big thanks to Yaros!

Thanks!
I think that will help a lot of routers:
https://wiki.dd-wrt.com/wiki/index.php/Supported_Devices#Asus

I think that, DNS server return IP address by name, but TechLife bulb use IP address and really DNS not return nothing. TechLife bulb used IP address of amazon MQTT server.

My lights atleast try to resolve cloud.qh-tek.com, so i changed it to return the ip address of my local mqtt server. works like a charm :wink:

If you’re of the soldering kind: https://templates.blakadder.com/unsupported/H4-E.html

There might be some alternative that does not involve changing the board to an esp8266.
The SM02A module the lamp uses has an RDA5981 SoC. If there is an easy way to read and write to its flash, maybe we can change any reference to “cloud.qh-tek.com” so that it points to another name (it can be a name that resolves to an private IP, so that it’s easier to set up)
There is probably a mechanism for doing OTA updates. I tried doing a port scan but it seems like the device is not listening on any particular port.