Skip to content

Commit dbeab1b

Browse files
authored
Release v2.3.0
2 parents d0984d1 + 6ac6ab5 commit dbeab1b

14 files changed

+200
-72
lines changed

README.md

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,52 +43,25 @@ On January 28th, 2019, Tuya started [distributing a patch](https://www.heise.de/
4343
# git clone https://github.com/ct-Open-Source/tuya-convert
4444
# cd tuya-convert
4545
# ./install_prereq.sh
46-
### flash loader firmware + backup
47-
# ./start_flash.sh
48-
49-
Follow the instructions in the start_flash script. It will install our flash loader onto the ESP and connect to the access point created by your wifi adapter.
50-
51-
WIFI: vtrust-flash
52-
IP: 10.42.42.42
53-
A backup of the original firmware will be created and stored locally
54-
55-
### Device information
56-
After the firmware backup procedure, the retrieved device information will be shown.
57-
Please make sure to write down your devices flash mode and size!
58-
You can show this information again by executing:
59-
60-
# curl http://10.42.42.42
61-
### BACKUP only and UNDO
62-
You can use the flash loader to create a backup only.
63-
If you want to delete the FLASH loader out of the flash again and go back to the stock software just do following:
64-
65-
# curl http://10.42.42.42/undo
66-
### FLASH loader to user2
67-
The FLASH loader only allows flashing the third party firmware if the loader is running in the userspace user2 starting from 0x81000.
68-
This will flash the FLASH loader in user2 if it is not already there.
69-
It will destroy your ability to undo and go back to the original firmware
70-
71-
# curl http://10.42.42.42/flash2
7246

7347
### FLASH third-party firmware
7448
BE SURE THE FIRMWARE FITS YOUR DEVICE!
75-
1. Place or link your binary file to ./files/thirdparty.bin.
49+
1. Place your binary file in the `/files/` directory or use one of the included firmware images.
7650

7751
Currently a Tasmota [v7.0.0.3](https://github.com/arendst/Tasmota/releases) `tasmota-wifiman.bin` build is included. You can update to a [current version](http://thehackbox.org/tasmota) via OTA after the Tuya-Convert process completes successfully. Please note that while we include this for your convenience, we are not affiliated with the Tasmota project and cannot provide support for post installation issues. Please refer to [the respective project](https://github.com/arendst/Tasmota) for configuration and support.
78-
52+
7953
An ESPurna [1.13.5](https://github.com/xoseperez/espurna/releases/tag/1.13.5) binary is also included (`espurna-base.bin`). Like before, the binary included does not have any specific hardware defined. Once flashed using Tuya-Convert you can update to the device-specific version via any of the means that ESPurna provides (OTA, web interface update, update via telnet or MQTT). Please refer to the [ESPurna project page](http://espurna.io) for more info and support.
8054

8155
Binary requirements:
82-
* full binary including first-stage bootloader
56+
* full binary including first-stage bootloader (tested with Arduino eboot and Open-RTOS rBoot)
8357
* maximum filesize 512KB for first flash
8458

8559
2. Start flashing process
8660

87-
# curl http://10.42.42.42/flash3
88-
89-
Alternatively you can request a certain file to be requested and flashed by the device:
90-
91-
# curl http://10.42.42.42/flash3?url=http://10.42.42.1/files/certain_file.bin
61+
Execute `./start_flash.sh` and follow the instructions.
62+
It will install our flash loader onto the ESP and connect to the access point created by your wifi adapter.
63+
A backup of the original firmware will be automatically downloaded and stored locally.
64+
You can then proceed to flash your desired firmware or revert to the stock firmware.
9265

9366
3. Initial Configuration
9467

File renamed without changes.
File renamed without changes.

files/upgrade.bin

-80 Bytes
Binary file not shown.

files/user2.bin

-247 KB
Binary file not shown.

scripts/fake-registration-server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def post(self):
113113
print(self.request.headers)
114114
if payload:
115115
try:
116-
decrypted_payload = unpad(AES.new(options.secKey, AES.MODE_ECB).decrypt(binascii.unhexlify(payload))).decode()
116+
decrypted_payload = unpad(AES.new(options.secKey.encode(), AES.MODE_ECB).decrypt(binascii.unhexlify(payload))).decode()
117117
if decrypted_payload[0] != "{":
118118
raise ValueError("payload is not JSON")
119119
print("payload", decrypted_payload)

scripts/firmware_picker.sh

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/bin/bash
2+
3+
MAGIC=$(printf "\xe9")
4+
5+
while true; do
6+
echo
7+
echo "Available options:"
8+
echo " 0) return to stock"
9+
index=0
10+
for file in ../files/*.bin; do
11+
# skip null glob
12+
[[ -e $file ]] || continue
13+
# get short name
14+
filename=$(basename "$file")
15+
# skip files too large or too small
16+
filesize=$(stat -c%s "$file")
17+
[[ "$filesize" -gt 0x1000 && "$filesize" -le 0x80000 ]] || continue
18+
# skip files without magic byte
19+
[[ $(head -c 1 "$file") == "$MAGIC" ]] || continue
20+
echo " $((++index))) flash $filename"
21+
options[$index]="$filename"
22+
# only show first 9 options, accessible with a single keypress
23+
if (( index == 9 )); then
24+
break
25+
fi
26+
done
27+
echo " q) quit; do nothing"
28+
echo -n "Please select 0-$index: "
29+
while true; do
30+
read -n 1 -r
31+
echo
32+
if [[ "$REPLY" =~ ^[0-9]$ && "$REPLY" -ge 0 && "$REPLY" -le $index ]]; then
33+
break
34+
fi
35+
if [[ "$REPLY" =~ ^[Qq]$ ]]; then
36+
echo "Leaving device as is..."
37+
exit
38+
fi
39+
echo -n "Invalid selection, please select 0-$index: "
40+
done
41+
42+
if [[ "$REPLY" == 0 ]]; then
43+
if curl -s http://10.42.42.42/undo; then
44+
echo "Disconnect the device to prevent it from repeating the upgrade"
45+
echo "You will need to put the device back into pairing mode and register to use again"
46+
else
47+
echo "Could not reach the device!"
48+
fi
49+
break
50+
fi
51+
52+
selection="${options[$REPLY]}"
53+
read -p "Are you sure you want to flash $selection? This is the point of no return [y/N] " -n 1 -r
54+
echo
55+
[[ "$REPLY" =~ ^[Yy]$ ]] || continue
56+
57+
echo "Attempting to flash $selection, this may take a few seconds..."
58+
RESULT=$(curl -s "http://10.42.42.42/flash?url=http://10.42.42.1/files/$selection") ||
59+
echo "Could not reach the device!"
60+
61+
echo "$RESULT"
62+
if [[ "$RESULT" =~ failed || -z "$RESULT" ]]; then
63+
read -p "Do you want to try something else? [y/N] " -n 1 -r
64+
echo
65+
[[ "$REPLY" =~ ^[Yy]$ ]] || break
66+
else
67+
if [[ "$selection" == "tasmota.bin" ]]; then
68+
echo "Look for a tasmota-xxxx SSID to which you can connect and configure"
69+
echo "Be sure to configure your device for proper function!"
70+
elif [[ "$selection" == "espurna.bin" ]]; then
71+
echo "Look for an ESPURNA-XXXXXX SSID to which you can connect and configure"
72+
echo "Default password is \"fibonacci\""
73+
echo "Be sure to upgrade to your device specific firmware for proper function!"
74+
fi
75+
echo
76+
echo "HAVE FUN!"
77+
break
78+
fi
79+
done
80+

scripts/mq_pub_15.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
from Crypto.Cipher import AES
2222
pad = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16)
2323
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
24-
encrypt = lambda msg, key: AES.new(key, AES.MODE_ECB).encrypt(pad(msg))
25-
decrypt = lambda msg, key: AES.new(key, AES.MODE_ECB).decrypt(unpad(msg))
24+
encrypt = lambda msg, key: AES.new(key.encode(), AES.MODE_ECB).encrypt(pad(msg))
25+
decrypt = lambda msg, key: unpad(AES.new(key.encode(), AES.MODE_ECB).decrypt(msg))
2626

2727
def iot_dec(message, local_key):
2828
message_clear = decrypt(base64.b64decode(message[19:]), local_key)

scripts/psk-frontend.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from hashlib import md5
1010
from binascii import hexlify, unhexlify
1111

12+
IDENTITY_PREFIX = "BAohbmd6aG91IFR1"
1213

1314
def listener(host, port):
1415
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -24,10 +25,15 @@ def client(host, port):
2425

2526
def gen_psk(identity, hint):
2627
print("ID: %s" % hexlify(identity))
28+
# sometimes the device only sends part of the prefix
29+
# since it is always the same, we can correct it
30+
if identity[1:17] != IDENTITY_PREFIX:
31+
print("Prefix: %s" % identity[1:17])
32+
identity = IDENTITY_PREFIX + identity[17:]
2733
key = md5(hint[-16:]).digest()
28-
iv = md5(identity[1:]).digest()
34+
iv = md5(identity).digest()
2935
cipher = AES.new(key, AES.MODE_CBC, iv)
30-
psk = cipher.encrypt(identity[1:33])
36+
psk = cipher.encrypt(identity[:32])
3137
print("PSK: %s" % hexlify(psk))
3238
return psk
3339

scripts/setup_ap.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ setup () {
3232
--address=/#/$GATEWAY
3333

3434
echo "Starting AP on $WLAN..."
35-
sudo hostapd hostapd.conf -i $WLAN
35+
36+
# Read hostapd.conf with interface from stdin for
37+
# backward compatibility (hostapd < v2.6). See #398
38+
printf "$(cat hostapd.conf)\ninterface=$WLAN" | sudo hostapd /dev/stdin
3639
}
3740

3841
cleanup () {

0 commit comments

Comments
 (0)