I found a chinese air quality sensor on Aliexpress. There doesn't seem to be a manufacturer associated with it. The device is simply called JQ-300. It contains an ESP-8266 and what looks like a SHARP GP2Y1010AUF0F (looks very similar to the dust sensor in the Sonoff SC)
I have attached pictures of the board and sensor.
@fastjack I'm about to buy one - have you tried to figure out how it communicates? It would be great if you can provide dump from WireShark or something like that. I was not able to find something usable about its protocol...
@ZdenekM I haven't tried reverse-engineering its protocol because I don't care about that. Once it's running ESPurna (or some other custom firmware) I don't intend to keep it sending data to the (chinese) cloud.
@fastjack Do you know of any custom firmware that could possibly run on this board? I'm also interested in no longer sending data away like it is doing now.
I do not understand how you prepare the data to get to the UUID.
2F6E28F52248B028FFFF4F36D15125A4CD222603856E2F5EF07B#487f4d81
ypyt_mqtt_server2F6E28F52248B028A6B8C1E18CC3603095631ACEBB087769F204A744C1AF7B5F9E5CC324B162CFF91AF55DB8845F0F444E973287EBB0F45D#cfa0dff8
What does the URL for retrieving my data look like?
Ok, I've come here so far.
http://www.youpinyuntai.com:32086/ypyt-api/api/app/deviceManager?platform=android&uid=8344&clientType=2&safeToken=7665895BDF40433AACC0A66443E16BAF&action=deviceManager
How do I get a list of the collected data?
One must take the trouble to solder out the memory chip, read out and change the address of the cloud.
@fastjack Hallo Herr Nachbar , interresse daran das mal offline zu diskutieren?
@ZdenekM
JQ300-filter IPnr-2.pcapng.txt
Old Capture JQ-300 -<-> Internet
One must take the trouble to solder out the memory chip, read out and change the address of the cloud. ...
@amimichael Hallo Nachbar, kein Problem. Meine Email-Adresse findest du in meinem Github-Profil
Sent with GitHawk
Ich habe mich mit dem AIR-Q Hersteller geschrieben, er meint : Hallo Michael,
auf der Leiterplattenoberseite sehe ich den Temperatur- und Luftfeuchtesensor oben links auf der kleinen Halbinsel. Rechts daneben mit den kreisförmig angeordneten Löchern ist wohl der VOC-Sensor. Der reagiert auch auf Formaldehyd, aber leider auch gleichtzeitig auf schlechten Atem und sonstige Ausgasungen, so dass man nicht sagen kann, ob wirklich eine gesundheitliche Belastung vorliegt. Vermutlich gibt er er als Formaldehyd den mit einem Faktor multiplizierten Wert von VOC aus. Dieser Sensor gibt noch eCO2 aus, also einen Wert, den CO2 haben müsste, wenn der gemessene VOC-Wert von menschlichen Ausdünstungen stammt - das stimmt nie. eCO2 anzugeben ist unserer Meinung nach Betrug am Kunden, weil hier eine Gewissheit vorgegeben wird, die nicht zutrifft.
I wrote to the AIR-Q manufacturer, he says hello Michael,
On the upper side of the PCB I can see the temperature and humidity sensor on the top left of the small peninsula. Right next to it with the circular holes is probably the VOC sensor. The responds to formaldehyde, but unfortunately also at the same time on bad breath and other outgassing, so that one can not say whether there is really a health burden. Presumably he gives it as formaldehyde multiplied by a factor of value of VOC. This sensor still emits eCO2, a value that CO2 would have to have if the measured VOC value came from human fumes - that's never true. eCO2 is in our opinion fraud on the customer, because here a certainty is given, which does not apply.
Hi folks, I was also interested in these units for a pre-made AQ sensor. (I am now a bit disappointed in how they have built the hardware).
Sharing a few random observations:
encrypted messages to devices include a leading FFFF which is not part of the encrypted payload. Suspect this may indicate encrypted payload, but not completely sure what this is for. Perhaps it's possible to send unencrypted payload.
ypyt_mqtt_server: seems to be where devices report their data. the first part of the message payload is the device id. these seem to be encrypted with device key_id of device_: seems to be where cloud sends control messages to deviceypyt_bingding_topic: seems to be something to do with initial provisioning (binding) to cloud. sometimes encrypted with device key, sometimes (maybe for initial communications) encrypted with master key_deviceToken?_: once apps bind with devices, there seems to be some provisioning of an app/listener id (10-byte device token) which emits unencrypted (json) payload stream of device data from cloud to app. I have seen this id to be encrypted into payload of some of the other provision messages from device.FE0025FF00#1164#1132#2200#5000#0415#2700#0000My hope was to reverse engineer this and write some script where I could just receive the data myself. However, due to the way they are dumping the device messages into a single big queue (rather than leveraging a topic naming hierarchy scheme, like device/{ID} where you could listen to all devices devices/#, or just one device) - for this reason I would _not_ recommend dumping their mqtt streams for long - it's alot of data, and you might get flagged/blocked, if they are smart enought to have rate limiting.
Also, sadly, while the device serial output shows the device id, but does not show the device key, so I was hoping to find some way of determining the key without dumping the flash. The only other way I see is to force factory re-provisioning (requires you to have some wifi ssids of "ypyttest1" and/or "ypyttest2" ready for device to connect to), then you can watch both serial output, and look for initial provisioning message (encrypted with master key) on cloud mqtt.
I think best plan is to reverse the esp to sensor mcu comms and find out a way to load custom firmware on the esp (although this would likely be only for advanced users due to desoldering of flash or mcu)
Outstanding work, @zerog2k!
I had previously investigated the mqtt implementation, but got nowhere close to what you got.
My initial idea was to replace it's remote server with a rogue local one and route all the data to a local machine, but I failed to parse the payload's contents. It's much clearer now, with your investigations!
Ok, I thought about this a bit more, and I think there are a few possibilities both with existing cloud (without using crap app) or without cloud (you somehow redirect the mqtt traffic to your own server [i.e. iptables, dns, etc])
First a bit about the initial provisioning (factory test) mode, which I think makes it possible to monitor via cloud. The idea here is that you can bypass the need of the app to setup the device and bind to cloud, and discover the application id (app_num_user ?) which is the topic you can subscribe to to get the cleartext json output of the device (what the app would see from the cloud).
The factory test/init process seems to go something like this:
Pxxxxxxx. There seems to be another 8 alphanumeric digit id starting with J, like Jyyyyyyy.Jyyyyyyyzzzzzz.ypyt_bingding_topic. Payload:E10020FFG#Jyyyyyyyzzzzzz#Pxxxxxxx#111111 - This appears to be "device_request_app_num_et_factory"Jyyyyyyyzzzzzz topic which seems to contain the "app_num", payload:E10032FFaaaaaaaaaaaaaaaa#bbbbbbbbbbbbbbbb#cccccccccccccccc - where a is the new provisioned "device id" (app_num ?), b is the "pkey" (device encryption key), and not sure yet what c isypyt_bingding_topic, payload:E10042FFV#Jyyyyyyyzzzzzz#Pxxxxxxx#111111#aaaaaaaaaaaaaaaa#bbbbbbbbbbbbbbbb - seems to be confirmation/acceptance of new device id and key (device_request_app_num_pkey_factory ?)Jyyyyyyyzzzzzz topic:E10004FF0040 - seems to be some test mode request? (data_test=0040)ypyt_bingding_topic:E10040FFT#Jyyyyyyyzzzzzz#aaaaaaaaaaaaaaaa#1#00#1302#1299#3000#4600#0000# - maybe some initial readings from sensors or other data?Jyyyyyyyzzzzzz:E10007FFT2#2700 - et_cloud.R0_value=2700 ?Jyyyyyyyzzzzzz:E10007FFT2#0000 - et_cloud.K_value=0000 ?now device seems to disconnect from initial provisioning topic, Jyyyyyyyzzzzzz, and now listens to topic aaaaaaaaaaaaaaaa
from here on, the encryption key used for all payloads is the device pkey negotiated above and encrypted device messages to ypyt_bingding_topic are prefixed w/ device id instead of FFFF (see encryption notes below).
device publishes message to ypyt_bingding_topic:
E30015FFaaaaaaaaaaaaaaaa#nnnn - seems to be device telling cloud where he is listening - although not sure what significance of nnnn is yet
cloud publishes message to aaaaaaaaaaaaaaaa:
E30014FFdddddddddddddddddddd - (device_request_app_num_user ?) d seems to be the topic id (aka deviceToken) which phone app connects to. Cloud publishes json payload of the sensor values to this topic - which is probably what we want to listen to and parse for long run.
from here seems to be basically repeating loop of device sending in data, with cloud ack'ing it, and sometimes some other control messages/heartbeats infrequently, e.g.:
ypyt_mqtt_server:FE0025FF00#1329#1304#2700#4400#0000#2700#0000 - (device_request_server_all_data) seems to be sending in the data values from sensorsaaaaaaaaaaaaaaaa:FA0002FFW2 - seems to be ack ?this mostly repeats forever
Another interesting aspect is how to get the device to connect to a wifi network _without_ the crap phone app.
You can use an ESP Smart Config app like DoIt's Esptouch or Espressif's Esptouch app, which will send wifi credentials to the app (via some udp/wifi frame broadcast magic voodoo). However, these devices need the password to be appended with some special magic token string (u9i9d9nnnn), where nnnn is some number (seems to be related to the E30015FFaaaaaaaaaaaaaaaa#nnnn message above?)
i.e., if your wifi is "password", you need to enter "passwordu9i9d9nnnn"
So theoretically, it's possible to (re)provision the device in order to get the pkey, such that you can get the deviceToken to monitor the device data, or perhaps we can just bypass the cloud mqtt and re-route to our own mqtt server, and fake the cloud?
A few other interesting observations about encryption:
FFFF, payload is encrypted with the factory key. If message starts with the device id, then the device pkey is used. (this can either be on ypyt_bingding_topic or ypyt_mqtt_server)FFEE instead of FFFF. Not sure if device ignores these or not. Hoping device would respect these as unencrpyted messages; perhaps we can make a "private" home cloud implementation easier by skipping some of the encryption dance.The slight downside with factory re-provisioning w/ cloud is that everyone listening can determine what your device id and pkey are now. (I'm not sure if there are nefarious things you can do if you know a particular device's pkey, like reset wifi credentials [knocking it offline] or maybe worst case, some OTA update)
The other option is to dump the flash of existing unit and you can get your id/key.
d: (E30014FFdddddddddddddddddddd)I have an example python script which will take this device token, listen to the mqtt topic, parse, and print out the sensor data. No need for app:
https://gist.github.com/zerog2k/b3afcaf3ff92a60474a159c7044dc8ce
Sat Jun 1 11:10:34 2019
message: sensor values
temp 21 C
hum 58 %
PM2.5 33 ug/m^3
HCHO 0.005 mg/m^3
TVOC 0.322 mg/m^3
eCO2 645 ppm
however, the data only as good as this device/cloud, i put it side by side with a Nordic Thingy (which also outputs TVOC, eCO2, etc) which seems to be slightly different on a few values, and not sure about the eCO2 and TVOC... (I think I would trust the Nordic design/quality better ;)
Easy way to get the device id:
I found out that the app makes HTTPS request to get the data in JSON format. Capturing traffic of it I found this is the request to look for:
https://www.youpinyuntai.com:31447/device/list?deviceToken=XXXXXXXXXXXXXXXXXXXXX&saveToken=SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS&uid=8228×tamp=1557220969315&tz=-2&type=1&page=0&&callback=jsoncallback&_=TTTTTTTTTTTTT
In particular, the device token (marked with X) and the _ parameter (marked with T) should be replaced with the real device token and the unix timestamp of the date when making the request (i.e. date "+%s on a linux machine). The S token is constant for me (I have 2 devices) but it might be a unique id for my application.
The JSON response is something like this:
{"returnCode":"0000","returnMsg":"成功","timestamp":0,"deviceValueVos":[{"content":"0","dptId":1,"seq":1},{"content":null,"dptId":1,"seq":2},{"content":null,"dptId":1,"seq":3},{"content":"26","dptId":1,"seq":4},{"content":"55","dptId":1,"seq":5},{"content":"33","dptId":1,"seq":6},{"content":"0.001","dptId":1,"seq":7},{"content":"0.220","dptId":1,"seq":8},{"content":"375","dptId":1,"seq":9},{"content":null,"dptId":1,"seq":10}],"deviceToken":"XXXXXXXXXXXXXXXXXXXXX"}
The response is quite simple and contains an array (deviceValueVos) with a seq parameter inside each element. The seq parameter seems to identify the read value following this table
4 -> Temperature
5 -> Humidity
6 -> PM 2.5
7 -> HCHO
8 -> TVOC
9 -> eCO2
I currently have a simple BASH script that uses CURL to fetch these info every 5 minutes without the use of the app.
I found out that the app makes HTTPS request to get the data in JSON format. Capturing traffic of it I found this is the request to look for:
https://www.youpinyuntai.com:31447/device/list?deviceToken=XXXXXXXXXXXXXXXXXXXXX&saveToken=SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS&uid=8228×tamp=1557220969315&tz=-2&type=1&page=0&&callback=jsoncallback&_=TTTTTTTTTTTTT
In particular, the device token (marked withX) and the _ parameter (marked withT) should be replaced with the real device token and the unix timestamp of the date when making the request (i.e. date "+%s on a linux machine). TheStoken is constant for me (I have 2 devices) but it might be a unique id for my application.The JSON response is something like this:
{"returnCode":"0000","returnMsg":"成功","timestamp":0,"deviceValueVos":[{"content":"0","dptId":1,"seq":1},{"content":null,"dptId":1,"seq":2},{"content":null,"dptId":1,"seq":3},{"content":"26","dptId":1,"seq":4},{"content":"55","dptId":1,"seq":5},{"content":"33","dptId":1,"seq":6},{"content":"0.001","dptId":1,"seq":7},{"content":"0.220","dptId":1,"seq":8},{"content":"375","dptId":1,"seq":9},{"content":null,"dptId":1,"seq":10}],"deviceToken":"XXXXXXXXXXXXXXXXXXXXX"}The response is quite simple and contains an array (
deviceValueVos) with aseqparameter inside each element. Theseqparameter seems to identify the read value following this table4 -> Temperature
5 -> Humidity
6 -> PM 2.5
7 -> HCHO
8 -> TVOC
9 -> eCO2I currently have a simple BASH script that uses CURL to fetch these info every 5 minutes without the use of the app.
Can you share your script?
@djbios My script is:
#!/bin/bash
timestamp=$((`date +%s` - 300))000;
request_url="https://www.youpinyuntai.com:31447/device/list?deviceToken=0DBB2CC60249A12B9000&saveToken=0062243D213348B2B5B249C92BA6000C&uid=3597×tamp=${timestamp}&&callback=jsoncallback&_=${timestamp}";
curl -ks ${request_url} | sed -E "s/jsoncallback\((.*)\)/\1/g" | jq --arg timestamp "${timestamp}" -r '.deviceValueVos | reduce .[] as $item (""; . + "," + ($item.content|tostring) + "," + ($item.dptId|tostring) + "," + ($item.seq|tostring)) | .+","+$timestamp' >> /home/pi/data/air_sensor/air_sensor_data.csv
@djbios My script is:
#!/bin/bash timestamp=$((`date +%s` - 300))000; request_url="https://www.youpinyuntai.com:31447/device/list?deviceToken=0DBB2CC60249A12B9712&saveToken=0062243D213348B2B5B249C92BA6A84C&uid=3597×tamp=${timestamp}&&callback=jsoncallback&_=${timestamp}"; curl -ks ${request_url} | sed -E "s/jsoncallback\((.*)\)/\1/g" | jq --arg timestamp "${timestamp}" -r '.deviceValueVos | reduce .[] as $item (""; . + "," + ($item.content|tostring) + "," + ($item.dptId|tostring) + "," + ($item.seq|tostring)) | .+","+$timestamp' >> /home/pi/data/air_sensor/air_sensor_data.csv
Unfortunately, this not works for me. I'am getting
jsoncallback({"returnCode":"0101","returnMsg":"您的账号已在其它地方登录","timestamp":0})
I've used deviceToken, saveToken and uid from mobile app request. And in my request "saveToken" was called "safeToken", but neither works.
UPD:
Somehow deviceToken was changed. I've updated it by
curl "www.youpinyuntai.com:32086/ypyt-api/api/app/deviceManager?uid=9923&clientType=2&safeToken=39D03B113FF042E6A8D70F0E2835E218&action=deviceManager", and now it works
@djbios you have to change the “deviceToken=“ , “saveToken=” and “uid=“ values to match your device.
I successfully created a PHP script that every minute via a cron job would pull the JSON via CURL to get the latest sensor values for my given device ID, used ID and save token.
However now it always is getting identical values every time it requests the data.
I notice by packet sniffing of the perthings app it looks like its JSON requests also always gets the same data back but mqtt requests (I think) are getting updated sensor values every few seconds.
Any idea why? Also can I use CURL to poll MQQT values rather than an MQQT client? I have curl setup nicely from PHP code to poll my multiple devices in parallel which makes the script very efficient, and am not familiar with using mqtt clients.
Any insight would be appreciated!
Does anyone know if there been any work on decoding the serial RX/TX between the ESP8266 and the other MCU inside of the device that is connected to all of the sensors? I'd really like to get this device off of the Internet and keep it intranet.
I suck at reverse engineering signals, but the nearest I can tell is that its a serial packet of 15 HEX values with the structure below. The temperature and humidity match what the app gives, but it seems odd do me that it would be calculations on the hex values though.
HEAD ALERT ??? TEMP HUM PM2.5 TAIL
59 50 FE 00 18 95 18 78 45 00 31 00 33 70 F0
ALERT - seems to be set to 02 when values are considered dangerous
Temperature (in C) = TEMP - 12 (33C = 45 - 12)
Humidity= HUM + 24 (55% = 31 + 24)
??? = I haven't figured out the structure for the CO2, HCHO, TVOC values
PM2.5 = Only these values (and ALERT) change when the PM2.5 sensor is disconnected
@jrmacleod this happens to me too: it happened in the past too, but it seems to be something related to their server. I don't know if it's a maximum requests cap they have or anything else, the last time I reset several times both devices and it worked again.
This time I'm going to wait for the data to be back in sync on their servers, let's see what happens!
Does anyone know if there been any work on decoding the serial RX/TX between the ESP8266 and the other MCU inside of the device that is connected to all of the sensors? I'd really like to get this device off of the Internet and keep it intranet.
I suck at reverse engineering signals, but the nearest I can tell is that its a serial packet of 15 HEX values with the structure below. The temperature and humidity match what the app gives, but it seems odd do me that it would be calculations on the hex values though.
HEAD ALERT ??? TEMP HUM PM2.5 TAIL 59 50 FE 00 18 95 18 78 45 00 31 00 33 70 F0ALERT - seems to be set to 02 when values are considered dangerous
Temperature (in C) = TEMP - 12 (33C = 45 - 12)
Humidity= HUM + 24 (55% = 31 + 24)
??? = I haven't figured out the structure for the CO2, HCHO, TVOC values
PM2.5 = Only these values (and ALERT) change when the PM2.5 sensor is disconnected
So I captured a few serial packet and here is what I think:
Now a few observations I have: it might be only on my device but that "1895 1878" is always in the form A B, where A and B are both 2 bytes in length and B is always smaller or equal to A. In fact, as soon as B reaches A, A is incremented by some quantities. This might be because those eCO2/TVOC/HCHO are all linked together, but still worth a note.
I was still not able to relate all the captures to the exact data that is sent to the cloud and I think those parameters are encoded in a way that could only be inferred by knowing the sensor used.
Anyone is able to identify those sensors so that we can lookup in the datasheets and see what format they use?
@lucamot,
Thank you for your reply and looking into this.
I also believe that the temperature and humidity are in HEX, like the rest of the packet. However, I wasn't able to get the values to correlate with the measured temperature in the app if I converted them to base 10. Adding the described decimal value to the HEX gave the same value in the APP for all values between 20-33C and 45-78% humidity. Still scratching my head on this one.
I forgot about the calibration done in the APP for humidity, so the formula(s) should be changed for this.
My PM2.5 sensor looks the GP2Y1010AU0F
The Temp/Humidity sensors looks like a HDC1080 chip.
I haven't been able to identify the MEMS chip that does the VOC, CO2, and HCHO sensing.
The MEMS chip package that I have looks different than the image at the top of this thread. (More holes in the can.)
Another update on this topic: I managed to dump the original firmware from the device (not the one shown on the picture above but the one on the new version of the board) and succeeded in flashing a custom firmware to the ESP (both Espurna and Tasmota, for the sake of curiosity). The operation seems quite complicated but it's easier than I thought since the RX pin is very accessible on the ESP8266 and the TX pin (the one associated with GPIO2) is linked to one of the test points on the board. Entering serial bootloader mode it's just a matter of shorting one of the pin of the blue/green led with the middle one (short the pin which is nearer to the ESP8266, it's connected to GPIO0).
The only thing I can confirm though is that every 3 seconds the ESP receives via UART rx pin the payload already mentioned in some posts above. The original firmware replies with the string "alldata_value_successful!\n" on the UART tx pin and then, after 40ms, it emits another string "device_request_server_all_data\n", again on the UART tx pin.
Unfortunately, I'm still not able to decode the string above to be used with different firmwares, if anyone has some ideas it's very welcome: my next though is to try to sniff the communication between the sensors and the MCU, but this might be a dead end since if the MCU re-encodes the values I might only have a mapping between values without knowing the real algorithm used.
You guys are way over my head but I can’t find any other place for help. I get hung up in the Perthings app at the time is says to “enter wifi name” so I enter my wifi name for 2.4 ghz wifi and hit next... and get an error of “please enter wifi name” I have rebooted phone, router and device... can’t get passed enter wifi name... any help would be hugely appreciated. TY.
Hi all,
I tried to decode temperature and humidity data and found the same results as jmw6773:
As PM2.5 sensor is analog - I connected a potentiometer between pins 4 (GND), 5 (Vin), 6 (+5V) and tried to change voltage and see reported data. As I said before - data is BCD encoded too. And it represent a voltage at pin 5 (Vin). 0V = 0000, 1V = 1000, 2.5V = 2500, etc. Maximum measured voltage is 4V = 3998, any greater voltage is reported as 3999.
Then I checked correspondence between voltage (or measured voltage) and PM2.5 value which is reported by Perthings application.
Result:
0900 - 244 ug/m3
0770 - 200 ug/m3
0700 - 175 ug/m3
0630 - 150 ug/m3
0578 - 125 ug/m3
0500 - 100 ug/m3
0440 - 75 ug/m3
0380 - 50 ug/m3
0212 - 25 ug/m3
0190 - 16 ug/m3
0163 - 7 ug/m3
0150 - 5 ug/m3
0144 - 1 ug/m3
The values have some deviations, it is not clear why. But in average it is ok. All greater values are reported as ">250ug/m3", so it is wasn't possible to measure them.
Is there a simple way to get the token id from the Android app? Or i have to sniff the traffic?
@AlexStankov
Could you clarify your results a little? Is the first value the measured Vin *100? (i.e. 1.5v on Vin pin = 0150)
If so, could you confirm that you're getting 9v?
Sorry, it's my fault. Range of 0V...4V is represented as 0000...3998. So 0900 means 0.9V.
@AlexStankov
Thank you for the explanation. That makes more sense.
I just noticed that the adjustment dial on my PM is in a different hole than what other GP2Y1010AU0F modules have. (The original post in this thread looks like mine.) You can also see resistors in the right 4 open holes. The GP2Y1010AU0F module doesn't have these resistors/caps.
I removed the back cover of my PM module and found a 2TY (PNP Transistor) a N81D (?), both in SOT-23, a 14-pin IC (the upper side has grooves in it, not sure if to remove all markings), and a boat load of resistors and capacitors.
Maybe our PM modules aren't Sharp, and don't follow the same dust curve as the GP2Y1010AU0F?
Or maybe the modules aren't analog and are actually outputting a PWM signal like the GP2Y1023AU0F module?
Comparison:
GP2Y1010AU0F
My Module (Sorry for the potato quality)
My sensor looks like your sensor. The chip is unmarked too. So looks like is it a Сhinese fake.
I'll try to check the sensor behavior by oscilloscope.
In case you’d like to reverse-engineer the firmware, I’ve written https://github.com/yath/ghidra-xtensa for the CPU but got stuck in provisioning mode and somehow forgot about it. I’ll try to reprovision it and/or try a different firmware to get an idea of the memory layout and how the other MCU’s data is processed, but I thought I’d share the processor module already.
Hi guys. I understand that this topic is about raw hardware hacking, but I faced a problem with this device and the Chinese reseller cannot help me with it. The mentioned device (JQ-300) started blinking blue lights and doesn't connect to 'perthings' app anymore. I just want to ask maybe this is some kind of safe mode or factory mode, and maybe there is a simple way to return this device to work.
the blue mode is for pairing with bluetooth or pairing other then wifi...
by ppressing and holding the button for 3 seconds and lettting go the light
should cycle and then start green again.... if you hold button in to long
like 7 second and then rel;ease you are entering a different pairing mode
then wifi aqnd yess should see blue blinking. if pressing and holding for 3
or 7 second doesnt change the pairing mode... then sorry but i dont know
anymore to help... good luck...
On Tue, Feb 4, 2020 at 7:17 AM AKuHAK notifications@github.com wrote:
Hi guys. I understand that this topic is about raw hardware hacking, but I
faced a problem with this device and the Chinese reseller cannot help me
with it. The mentioned device (JQ-300) started blinking blue lights and
doesn't connect to 'perthings' app anymore. I just want to ask maybe this
is some kind of safe mode or factory mode, and maybe there is a simple way
to return this device to work.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/xoseperez/espurna/issues/1644?email_source=notifications&email_token=AN4ABEOMXCMEMLEBFCJBF3LRBFMENA5CNFSM4HADPCDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKXNQQQ#issuecomment-581883970,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AN4ABEMGFQQOHREHWDHMCE3RBFMENANCNFSM4HADPCDA
.
by ppressing and holding the button for 3 seconds and lettting go the light should cycle and then start green again....
…
On Tue, Feb 4, 2020 at 7:17 AM AKuHAK @.*> wrote: Hi guys. I understand that this topic is about raw hardware hacking, but I faced a problem with this device and the Chinese reseller cannot help me with it. The mentioned device (JQ-300) started blinking blue lights and doesn't connect to 'perthings' app anymore. I just want to ask maybe this is some kind of safe mode or factory mode, and maybe there is a simple way to return this device to work. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#1644?email_source=notifications&email_token=AN4ABEOMXCMEMLEBFCJBF3LRBFMENA5CNFSM4HADPCDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKXNQQQ#issuecomment-581883970>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AN4ABEMGFQQOHREHWDHMCE3RBFMENANCNFSM4HADPCDA .
Thank you this helped a lot! I didnt released before button after 3 seconds, now everything is fine.
good to hear. welcome. yes i had similar trouble with setup
On Thu, Feb 6, 2020 at 5:46 AM AKuHAK notifications@github.com wrote:
by ppressing and holding the button for 3 seconds and lettting go the
light should cycle and then start green again....
… <#m_6749222344186149057_>
On Tue, Feb 4, 2020 at 7:17 AM AKuHAK @.*> wrote: Hi guys. I
understand that this topic is about raw hardware hacking, but I faced a
problem with this device and the Chinese reseller cannot help me with it.
The mentioned device (JQ-300) started blinking blue lights and doesn't
connect to 'perthings' app anymore. I just want to ask maybe this is some
kind of safe mode or factory mode, and maybe there is a simple way to
return this device to work. — You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#1644
https://github.com/xoseperez/espurna/issues/1644?email_source=notifications&email_token=AN4ABEOMXCMEMLEBFCJBF3LRBFMENA5CNFSM4HADPCDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKXNQQQ#issuecomment-581883970>,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AN4ABEMGFQQOHREHWDHMCE3RBFMENANCNFSM4HADPCDA
.Thank you this helped a lot! I didnt released before button after 3
seconds, now everything is fine.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/xoseperez/espurna/issues/1644?email_source=notifications&email_token=AN4ABEO4MLYH6T7YR7UUBV3RBPTBRA5CNFSM4HADPCDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEK6YEJI#issuecomment-582844965,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AN4ABEOHCMXUZRXWN66TFULRBPTBRANCNFSM4HADPCDA
.
Guys, there is an absolutely easy way to get the device id if you have a rooted phone with the Perthings app.
The device id is stored plain text in the app database. You can read the database with SQLite database editor (by Supertommino) from Google Play store. The Perthings app needs to be in device internal memory, not sd card (you can use Titanium backup to move it). Just open the editor, choose Perthings -> im.db and look for the mqttTopic record. You can copy it out to use with zerog2k's script (thanks a lot for it!!).
Another update on this topic: I managed to dump the original firmware from the device (not the one shown on the picture above but the one on the new version of the board) and succeeded in flashing a custom firmware to the ESP (both Espurna and Tasmota, for the sake of curiosity). The operation seems quite complicated but it's easier than I thought since the RX pin is very accessible on the ESP8266 and the TX pin (the one associated with GPIO2) is linked to one of the test points on the board. Entering serial bootloader mode it's just a matter of shorting one of the pin of the blue/green led with the middle one (short the pin which is nearer to the ESP8266, it's connected to GPIO0).
The only thing I can confirm though is that every 3 seconds the ESP receives via UART rx pin the payload already mentioned in some posts above. The original firmware replies with the string "alldata_value_successful!\n" on the UART tx pin and then, after 40ms, it emits another string "device_request_server_all_data\n", again on the UART tx pin.
Unfortunately, I'm still not able to decode the string above to be used with different firmwares, if anyone has some ideas it's very welcome: my next though is to try to sniff the communication between the sensors and the MCU, but this might be a dead end since if the MCU re-encodes the values I might only have a mapping between values without knowing the real algorithm used.
Hey @lucamot, could you possibly explain in nore detail how were you able to dump the firmware, which test ports did you use, or even provide the firmware you dumped?
I'm trying to extract the firmware but without luck so far.
My board is exactly the same as the one photographed in the first post.
Thank you very much.
Oh, I would really like this thing reverse engineered for HASS.io integration and other thing. In fact after reading this issue I decided to buy a JQ-300 myself for doing some reverse engineering later myself.
_Quite a scam. I bought a JQ-300 according to my order, it looks from the outside like a JQ-300 based on the English description manual (apparently only JQ-300 has the round airhole in the middle) and mine has also, but compared to the photos of the inside above and the device I have it's clearly lacking an pm2.5 sensor making it simply a JQ-200 instead. The package has three unchecked options for JQ-100, JQ-200 and JQ-300. And a JQ-200 sticker was added on the box as sealing. Funny thing is that when connected to the app it also shows it's a JQ-300 but it lacks the PM2.0 information entirely._
_Also connecting it to the app didn't go without problems. I could not install the app from the play store on Android so I had to install a shady APK which was pointed out using a QR code on the package. The app did not work properly at all and could not determine my SSID so I was unable to pair the device to my network. Then on an iphone I could install it from the App Store and managed to finally bind the device to my account._
BTW here's integration for HomeAssistant
https://community.home-assistant.io/t/jq-300-200-100-indoor-air-quality-meter/189098
I wonder if this can be tasmotised?
which test ports did you use
Looking at the board photo:
GPIO0 is the letter B by the led. Short this to the centre to put the device in programming mode. (leave it there)
GPIO2 is the left hand thruhole land adjacent to "JQPM-1 V3.0" (the right hand one is ground)
The track under the + is 3.3V (also top left pin of U6)
the pin marked c is pin1 (numbering is counterclockwise)
GPIO4 appears to link to S1 (not connected)
GPIO5 seems to go to the green led
Normally you'd use pins 25(rx) and 26(tx) for this job (bottom row of the ESP2566, left pair of pins), but these dive off under U5, emerging at U5 pin 11 and 12 respectively (13 goes to pin 32 on the ESP - RST). If you want to try bootloading using those pins I'd suggest pulling the Sharp sensor first and feeding in an external 3.3V supply, as it appears the UART has a separate feed from the 5V supply via U7
A lot of the time these blanked out chips have been painted over. I'm going to try an acetone attack and see if it helps identify the thing
(EDIT: nope, acetone didn't work. These really do seem to be some kind of unbranded a/d converter)
the blue mode is for pairing with bluetooth or pairing other then wifi...
Actually it's for pairing with a "YPLINK hotspot" - SSID: aaa PASS: 12345678 (yeah, really secure)
I can make that work with my android on the perthings app, but it will not reset to the house wifi (perhaps because I have !"$%^&*()_=?+-<>@ characters in the password - they're US-ASCII and should be allowed but I've seen worse dainbramaged behaviour in the past)
EDIT: You can change the ssid and password for the AP in the Perthings app, but contrary to the instructions the light stays blue even if you pair it with your home AP. Setting it back into the flashing green pairing mode clearly isn't supported in the android app and will fail if you attempt to do so. It's working happily on my home Wifi in solid blue led mode (having set it away from ssid aaa) and seems to be phoning home
If you're uneasy about having a "rogue" device on your wifi then I suggest you do what i do and put it on the guest network (I have a Fritz Box, this has a guest WIFI SSID and guest LAN network). Due to widespread attacks on login/passwords you would be extremely silly to use a non-unique login/pass for the perthings cloud
Back on trying to hack into this thing and tasmotize it
@lucamot - what pins were you using? The standard GPIO1/GPIO3 pair don't work
I think that the sensor could be interrogated periodically on Tasmota with a simple rule, for example:
Rule1 ON Rules#Timer=1 DO Backlog SerialSend1 device_request_all_data ENDON ON SerialReceived#Data DO Backlog SerialSend1 alldata_value_successful!; RuleTimer1 3 ENDON
Rule1 1
RuleTimer1 3
Does anyone recall which baud is used on UART connection to external MCU?
Tried that, but without correct baud, to no avail.
Got some moderate success on Tasmota with this template:
{"NAME":"JQ-300","GPIO":[290,3200,1,3232,1,289,1,1,1,288,1,1,1,1],"FLAG":0,"BASE":18}
And the following configuration in console:
SerialConfig 8N1
Baudrate 230400
SerialDelimiter 255
Rule1 ON System#Boot SerialSend4 "device_request_all_data\n"
Rule1 on
Then after sending empty string, built-in MCU starts spewing out data - Not sure if the baud is still correct. Frames repeat every 3s, but vary with contents slightly:
13:53:21 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066987866187806180618661E00"}
13:53:21 QPC: Reset
13:53:25 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066187E66987806180618661818"}
13:53:28 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066987E66187E06180618661818"}
13:53:31 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066987E6698E666180618666600"}
13:53:34 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"86666600661866187E66180618660018"}
13:53:38 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"86666600661866187E66180618667E00"}
13:53:41 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"866666006698F866188066180618667800"}
13:53:45 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"866666006698006698F866180618660018"}
13:53:48 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"866666006698006698000618061866868000"}
13:53:52 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"866666006698006698F866180618661800"}
13:53:55 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"86666600669800661866180618661860"}
13:53:58 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066980066980006180618660018"}
13:54:02 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066980066980006180618661818"}
13:54:05 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066980066180618061866808000"}
13:54:09 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"866666006698006698F866180618666018"}
13:54:12 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066180066980006180618661E18"}
13:54:16 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"8666660066180066980006180618667860"}
I guess I'll just use my logic analyze to probe for correct baud - it looks like sending literally anything triggers secondary MCU to send data. @Stoatwblr you might want to try out my configuration - it looks like standard GPIO1/GPIO3 configuration is indeed correct.
I may have gone a little overboard on this, but I've tried to annotate the board image to help with debugging
My unit has a v3.5 board but there seems to be almost no difference apart from slight layout tweaks, a change of the TVOC PNP driver transistor type (this isn't critical, it's mainly driving the TVOC heater) and addition of S3 pads on the component side of the board which merely duplicates S2

Got some moderate success on Tasmota with this template:
How did you manage to tasmotize it?
If I tie down gpio0 then I can't talk to the ESP8266 (standard way of putting device into programming mode)
tieing down EXT_RSTB appears to prevent the ESP8266 booting up at all (rather than blocking U5 from transmitting)
I get the impression that U5 is a pretty dumb device
Got some moderate success on Tasmota with this template:
How did you manage to tasmotize it?
If I tie down gpio0 then I can't talk to the ESP8266 (standard way of putting device into programming mode)
tieing down EXT_RSTB appears to prevent the ESP8266 booting up at all (rather than blocking U5 from transmitting)I get the impression that U5 is a pretty dumb device
I struggled with connecting UART too, despite putting it in programming mode, so I did a chip-off and used CH341A-based SPI flash programmer together with flashrom. I needed to dump an empty flash and "patch" it with some xxd hackery for flashrom to not complain about Tasmota image being to small for the device. Something along the lines of cat <(xxd empty_flash.bin) <(xxd tasmota.bin) | xxd -r > tasmota-fullflash.bin.
If you hold EXT_RSTB low, you might have some luck with programming SPI-flash using a clip, if you have one available, this should avoid the chip-off.
Turns out that mere 115200bps is the correct baud. Who knew.
00:16:31 CMD: BaudRate 115200
00:16:31 SER: Set to 8N1 115200 bit/s
00:16:31 RSL: stat/tasmota_8F0A5B/RESULT = {"Baudrate":115200}
00:16:34 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382736280025000445F0"}
00:16:37 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000428F0"}
00:16:40 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000449F0"}
00:16:44 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000439F0"}
00:16:47 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382734280025000430F0"}
00:16:51 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000451F0"}
00:16:54 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735270025000433F0"}
00:16:58 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735270026000421F0"}
00:17:01 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735270026000440F0"}
00:17:04 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382736270026000470F0"}
00:17:08 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382728270026000448F0"}
00:17:11 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382734270026000456F0"}
00:17:15 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382734280026000463F0"}
00:17:18 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280026000442F0"}
00:17:22 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382734280026000426F0"}
00:17:25 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000446F0"}
00:17:29 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000443F0"}
00:17:32 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382736280025000454F0"}
00:17:35 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000451F0"}
00:17:39 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000417F0"}
00:17:42 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382734280025000439F0"}
00:17:46 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382722280026000438F0"}
00:17:49 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000439F0"}
00:17:53 RSL: tele/tasmota_8F0A5B/RESULT = {"SerialReceived":"5950FE0027382735280025000449F0"}
So the proper config would be:
SerialConfig 8N1
Baudrate 115200
SerialDelimiter 255
Rule1 ON System#Boot SerialSend4 "device_request_all_data\n"
Rule1 on
I have some pogo pins on the way in order to 3dprint a chip clip on other devices. I'll make a clip for the SPI and try that, although I wonder if lifting the MCU might work
We really do need to find a way of breaking into these things without needing to get too fancy. All this work is defeating the attraction of the cheapness of the device
A lot of the time these blanked out chips have been painted over. I'm going to try an acetone attack and see if it helps identify the thing
(EDIT: nope, acetone didn't work. These really do seem to be some kind of unbranded a/d converter)
I think, U5 is a microcontroller. Perhaps a PIC16F688 or PIC16F1824. Both have UART, I2C and a 8Ch 10Bit ADC. Only the assignment of Rx (Pin5) and Tx (Pin6) does not match the layout. And i dont't think they are using software serial at 115200 when the hardware UART is othewise unused... Also SDA ans SCL do not match.
However, the UART-Pins match for the AtTiny804, but not the SCL/SDA (which is no big deal with software-i2c)
Maybe it is just some chinese 5ct microcontroller.
Thanks @Leo-PL
On a JQ-200 (no dust sensor), was able to flash Tasmota 9.2.0 with flash chip in-circuit with an 8 pin clamp and pulling pin 13 (esp nrst) low on the U5 namless mcu. I ordered a wch341a chip (darned buspirate is just too slow). (I wasted troubleshooting time trying to use minimal build to find out that doesn't work properly), and then get the serial strings pumping out to mqtt. Will lash up a python script for reading and decoding from mqtt if I get a chance.
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522152190032000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021542152190033000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522142190033000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522143190033000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522150190034000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522142190033000000F0"}
tele/tasmota_CFD737/RESULT {"SerialReceived":"5950FE0021522143190033000000F0"}
goodbye craptastic ypyt
I'll also try this on my JQ-300 (which has dust sensor attached).
also observed that if I hold down the button on the back (which is connected to u5 mcu):
{"SerialReceived":"5950F3909090F0"}{"SerialReceived":"5950F4000000F0"}It may make sense to check for those, and trigger deep sleep, the reset line on "unknown" MCU connected to ESP2866 NRST is likely output to wake ESP up.
ok got some basic output working (TODO: parse and send to influxdb/grafana)
https://gist.github.com/zerog2k/804feb1d9159bf5610be89d6662e5749
$ ./tasmota_sensor_parse.py tele/+/RESULT
Connected with result code 0
Sun Jan 17 15:20:56 2021 tele/tasmota_CFD737/RESULT
msg: a=2279 b=2262 temp=21 hum=30 dust=0000
Sun Jan 17 15:20:59 2021 tele/tasmota_D3D1A7/RESULT
msg: a=2439 b=2421 temp=25 hum=27 dust=0556
Sun Jan 17 15:21:00 2021 tele/tasmota_CFD737/RESULT
msg: a=2279 b=2262 temp=21 hum=30 dust=0000
Sun Jan 17 15:21:02 2021 tele/tasmota_D3D1A7/RESULT
msg: a=2439 b=2422 temp=25 hum=27 dust=0526
Sun Jan 17 15:21:03 2021 tele/tasmota_CFD737/RESULT
msg: a=2279 b=2262 temp=21 hum=30 dust=0000
note the significant temperature and humidity variance between two units sitting next to each other in same room
The a and b values as discussed earlier in this thread seem to be some raw values relating to hcho/tvoc/eco2, but not sure what they are. Does anybody know what sensor is being used? (anybody sniff the i2c or whatever to get an idea of the register set in use, to possibly identify the chip being used?)
I did observe when putting a napkin soaked with isopropyl alcohol near the unit, the b value started to decrease rapidly (into 1600's), whilea value stayed about the same.
Not really sure what units this is (raw mV, etc)?
"Normally" these two values seem to be about the same.
I was able to install Tasmota on my board tonight by flashing the Winbond flash using chip-clip and bridging EXT_RSTB to GND. No need to remove the flash from the board. Thanks @Leo-PL for the xxd commands.
If you compile Tasmota with scripting enabled and MAXSVARS set to at least 7, you can parse the serial string and publish it directly to MQTT. If previous testing, temperature and humidity needs to be offset (Temp-12, hum+24). I'm not sure if it's possible to convert a string to int in Tasmota directly, so this would need to be done by the receiving system.
>D 35
is=""
tmp=""
a=""
b=""
temp=""
hum=""
dust=""
>BS
=>SerialConfig 8N1
=>Baudrate 115200
=>SerialDelimiter 255
=>SerialSend4 "device_request_all_data\n"
>E
is=SerialReceived
tmp=sb(is 0 4)
if tmp=="5950"
then
if sl(is)==14
then
a=sl(is 4 2)
switch a
; short press "5950F3909090F0"
case "F3"
->wakeup
; long press "5950F4000000F0"
case "F4"
->restart
ends
endif
if sl(is)==30
then
; data packet
a=sb(is 8 4)
b=sb(is 12 4)
temp=sb(is 16 2)
hum=sb(is 20 2)
dust=sb(is 24 4)
; publish data
=>Publish tele/%topic%/SENSOR {"a": %a%, "b": %b%, "temp": %temp%, "hum":%hum%, "dust":%dust }
endif
endif
Outputs:
{"a": 2322, "b": 2307, "temp": 31, "hum":66, "dust":0410}
@jmw6773 thanks a lot for the script, I'll try it out for sure.
+1 thanks for the script - I was planning on looking into tasmota scripting, but you managed to solve it, yay!
a few random notes:
%topic%: it's resulting in tasmota_%02X rather than tasmota_ABCDEF. I'm researching more, and will likely open an issue if I cant fix.R_s/R_0. Seems to me that a may be some kind of maximum voltage reading (maybe for baseline/calibration?), and b may be current voltage reading? Just guesses.My initial suspicions are that this TVOC MEMS sensor _may_ be a GM-502B
https://www.winsen-sensor.com/d/files/PDF/MEMS%20Gas%20Sensor/mems--voc--gm-502b--manual%EF%BC%88ver1_1%EF%BC%892017_5_10.pdf
The way the sensor is wired in w/ MCU, it may be:
Vcc -- Rl -- Vs -- Rs -- GND
where: Vcc = 3.3v, Rl = 47kohms, Vs is sensor output (a or b values in mV), and Rs is the sensor's equivalent resistance
Given this, I think the correct relationship is:
Vs = Vc ( Rs / [Rs+Rl] )
So I _think?_ that yields:
Rs = (Rl*Vc) / (Vc-Vs)
and a is Vs of R0, and b is Vs of Rs (in mV)
if this makes sense?
Someone please check my work ;)
Would anyone be able to share the dumped firmware for analysis? I think there could be something to be learned from it - like getting to do an OTA update to Tasmota.
@zerog2k
Thanks for the pointers.
jq300, it publishes to the correct topic (tele/jq300/SENSOR)There is some information on a suspiciously similar looking board that matches this: https://www.alibaba.com/product-detail/Integrated-Air-quality-sensor-module-for_1600137315460.html
Some more information about the protocol: https://pdf.directindustry.com/pdf/jinan-rainbow-technology-co-ltd/indoor-air-quality-sensor-module/224565-935992.html
Thanks @fabbarix
I suspect that you are right that Jianan Rainbow Tech is probably behind the hardware development of the JQ-200/300, but while similar, the protocol seems a bit different from what you posted vs what is observed.
However, looking at other rainbowtech stuff, seems like the VOC sensor may be S1013V and here is a good "datasheet" for it:
http://www.rainbowtechnology.cn/productinfo/1487.html
I'm pretty sure that the values of a & b are the voltage output (in mV) from the MEMS sensor. I observed this myself while measuring the voltage divider network output (Vs) from the sensor, and verified it's the b value.
I'm not sure if there is a way to have the mcu calculate this directly - perhaps there is some other data output package which can be obtained. However, I think you can calculate the Rs/R0 relationship from Vs, and seems like you can then derive the ppm concentration of various gases by log-log regression? from their charts. (What the jayconsystems link above discusses.) Edit: seems like it may also need to be corrected for temperature & humidity as well.
Edit2: the responses here also useful for discussion: https://electronics.stackexchange.com/questions/388548/how-to-calculate-gas-sensor-ppm-from-analog-readings - TLDR; _it's not so simple, and not so accurate_ ;)
To open up the casing of this units: there are two screws on the bottom, where the USB port and reset button are. The screws are hidden behind a plastic mask that can be peeled off with a plastic pryer.
There are also three plastic clips, two on the sides and one on the top. After removing the screws you can gently pry the unit open using leverage between the stand and the back cover.


Would anyone be able to share the dumped firmware for analysis? I think there could be something to be learned from it - like getting to do an OTA update to Tasmota.
I wonder how to do it without breaking Github rules or the law. In any case, I backed up mine for this very purpose.
Can you share the strings and binwalk results on the firmware dump? It's also a good way to figure out if there is any GPL code in it.
Can you share the
stringsandbinwalkresults on the firmware dump? It's also a good way to figure out if there is any GPL code in it.
Here you are, results of strings and binwalk:
Wait a minute.... There is a private RSA key in the firmware? Rarely a good sign in security! :/
Update: jumped the gun on this one! 🤦 That seems to be a false positive coming from the string template used to load the certificate, at least by looking at the string dump. Got my clip today to get the firmware out.
Yeah, laughed hard after seeing this ;-)
It might be worthwhile if we hit up on private, and compare full binary dumps, too.
@fabbarix @Leo-PL Count me in as well for that binary please, I've been following this with attention and I do have a couple of those devices coming in my mail soon enough ;)
@Leo-PL Tried to dump my firmware, but it's reading junk. When you pull down PIN 13 of U5 do you keep it at ground? Are you using the 1.8v adapter or plain CH341A?
@Leo-PL Tried to dump my firmware, but it's reading junk. When you pull down PIN 13 of U5 do you keep it at ground? Are you using the 1.8v adapter or plain CH341A?
You can use the ch341a with 8-pin soic chip clip, and keep pin 13 of U5 at ground (which should hold ESP in reset, and not interfere with the flash operations)
I was able to dump just fine.
Beware, the dump will contain some settings which are unique to your config such as SSID/Passwords, and maybe other stuff, so beware during sharing)
@Leo-PL Tried to dump my firmware, but it's reading junk. When you pull down PIN 13 of U5 do you keep it at ground? Are you using the 1.8v adapter or plain CH341A?
I did a chip-off with ZIF socket and plain CH341A, so I didn't have to bother with holding EXT_RSTB low. But even with trying to pull it low, flashromm wouldn't detect the flash on my board - hence the chipoff.
@fabbarix I was able to detect the flash and get a dump using CH341A and software in Windows. I cut a female jumper wire in half, soldering the cut in to the pin on U5 and the female connector into the GND of the dust sensor connector.
Make sure you power the board using 3.3v and not the USB connector. This should prevent the 2nd IC from booting and trying to start the ESP.
Powering the device from USB connector would indeed explain my experience.
Thanks @Leo-PL
On a JQ-200 (no dust sensor), was able to flash Tasmota 9.2.0 with flash chip in-circuit with an 8 pin clamp and pulling pin 13 (esp nrst) low on the U5 namless mcu
I've just "kind of" duplicated this feat using a ch341a_spi programmer to read the chip https://www.aliexpress.com/item/4001045543107.html?spm=a2g0s.12269583.0.0.43f577c3QuLfnb
SSID and pass are stored in cleartext in the generated image (twice) at 0x0007D010, along with a bunch of other bits and pieces
0x0007D000: FCE4FFFF FFFFFFFF 0100FFFF 0A000000 ................
SSID here:
0x0007D010: xxxxxxxx xxxxxxxx xxxxxxxx 00000000 xxxxxxxxxxxx.....
0x0007D020: 00000000 00000000 00000000 00000000 ................
Pass here:
0x0007D030: 03050300 03000057 xxxxxxxx xxxxxxxx .......xxxxxxxxx
0x0007D040: xxxxxxxx xxxxxxxx xxxxxxxxx xxxxxxxx xxxxxxxxxxxxxxxx
0x0007D050: xxxxxxxx 00000000 00000000 00000000 xxxx............
0x0007D060: 00000000 00000000 00000000 00000000 ................
What's this?
0x0007D070: 00000000 00000000 78D7A455 EADCAEB0 ........x..U....
0x0007D080: A9490ABC B7BB5602 DF752F96 302B5AB3 .I....V..u/.0+Z.
0x0007D090: 9C5F02E0 4720DF8B FFFFFFFF FFFFFFFF ._..G ..........
0x0007D0A0: FFFFFFFF FFFFFFFF FF008C53 C3E8AA03 ...........S....
0x0007D0B0: 0A000000 4553505F 38453841 39420000 ....ESP_8E8A9B..
0x0007D0C0: 00000000 00000000 00000000 00000000 ................
"ESP_8E8A9B" is how it appeared in the local network
0x0007D0D0: 00000000 00000000 00000000 00000000 ................
0x0007D0E0: 00000000 00000000 00000000 00000000 ................
0x0007D0F0: 00000000 00000000 00000000 00000000 ................
0x0007D100: 00000000 00000000 00000000 00000000 ................
0x0007D110: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF ................
0x0007D120: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF ................
0x0007D130: FFFFFFFF FF010000 04FFFFFF 0100FFFF ................
SSID again
0x0007D140: 0A000000 xxxxxxxxx xxxxxxxxx xxxxxxxxx ....xxxxxxxxxxxx
0x0007D150: 00000000 00000000 00000000 00000000 ................
Password again
0x0007D160: 00000000 xxxxxxxx xxxxxxxx xxxxxxxx ....xxxxxxxxxxxx
0x0007D170: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxxxxxxxxx
0x0007D180: 00000000 00000000 00000000 00000000 ................
0x0007D190: 00000000 00000000 00000000 00000000 ................
0x0007D1A0: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF ................
It's 0xff from here down to
0x0007E000: FCE4FFFF FFFFFFFF 0100FFFF 03000000 ................
flashing blue mode?
Key = aaa (and remnants of SSID preivously set here)
0x0007E010: 61616100 xxxxxxxx xxxxxxxx 00000000 aaa.xxxxxxxx.....
0x0007E020: 00000000 00000000 00000000 00000000 ................
that wildly insecure password again (and remnants of previously set password)
0x0007E030: 03050300 03000131 32333435 36373800 .......12345678.
0x0007E040: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxxxxxxxxxx
0x0007E050: xxxxxxxx 00000000 00000000 00000000 xxxx............
0x0007E060: 00000000 00000000 00000000 00000000 ................
0x0007E070: 00000000 00000000 78D7A455 EADCAEB0 ........x..U....
0x0007E080: A9490ABC B7BB5602 DF752F96 302B5AB3 .I....V..u/.0+Z.
0x0007E090: 9C5F02E0 4720DF8B FFFFFFFF FFFFFFFF ._..G ..........
0x0007E0A0: FFFFFFFF FFFFFFFF FF008C53 C3E8AA03 ...........S....
0x0007E0B0: 0A000000 4553505F 38453841 39420000 ....ESP_8E8A9B..
0x0007E0C0: 00000000 00000000 00000000 00000000 ................
0x0007E0D0: 00000000 00000000 00000000 00000000 ................
0x0007E0E0: 00000000 00000000 00000000 00000000 ................
0x0007E0F0: 00000000 00000000 00000000 00000000 ................
0x0007E100: 00000000 00000000 00000000 00000000 ................
0x0007E110: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF ................
0x0007E120: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF ................
0x0007E130: FFFFFFFF FF010000 04FFFFFF 0100FFFF ................
and again
0x0007E140: 03000000 61616100 xxxxxxxx xxxxxxxxx ....aaa.xxxxxxxx
0x0007E150: 00000000 00000000 00000000 00000000 ................
0x0007E160: 00000000 31323334 35363738 00xxxxxx ....12345678.xxx
0x0007E170: xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxxxxxxxxx
0x0007E180: 00000000 00000000 00000000 00000000 ................
0x0007E190: 00000000 00000000 00000000 00000000 ................
If someone would like to analyse the image and see if this can be kludged for OTA upgrade, please let me know (it's only 256kB gzipped)
EDIT: There's a LOT of plaintext in this thing, including what appears to be a complete set of debuigging symbols, possibly built in -g mode
Not sure if there is a direct way to force local ota update, but I hinted at it before. I'm guessing there is some command messages coming over mqtt which could force update/reprovision/ota, etc.
I don't recall any local api ports open from nmap scan on which you could try to poke on to force some local ota update.
Best of luck for OTA hunting!
Not sure if there is a direct way to force local ota update
Judging from the plaintext in order to attempt to thwart being put into a sandbox it looks up whatismyip.com and wikipedia before going to http://173.194.45.65 and http://www.youpinyuntai.com:32413/link/fastLink
$ binwalk /tmp/jq300.img
248212 0x3C994 SHA256 hash constants, little endian
349456 0x55510 CRC32 polynomial table, little endian
355452 0x56C7C PEM RSA private key
355552 0x56CE0 PEM certificate
$ esptool image_info /tmp/jq300.img
esptool.py v2.8
Image version: 1
Entry point: 40100294
3 segments
Segment 1: len 0x00574 load 0x40100000 file_offs 0x00000008 [IRAM]
Segment 2: len 0x00308 load 0x3ffe8000 file_offs 0x00000584 [DRAM]
Segment 3: len 0x0021c load 0x3ffe8308 file_offs 0x00000894 [DRAM]
Checksum: c0 (valid)
@Stoatwblr it'd be great if you could get in touch with @fabbarix with the binary, so we can all compare them and look for differences in dumps.
I have been following this thread for a while. I have 2 identical units and have ordered the programmer @Stoatwblr linked to (thanks!). I am a bit newcomer to reverse engineering, but I would love to give it a try. Would you mind sending me a dump and I'll try my best?
send me a private message and I'll fire it over. As the image contains my SSID and Wifi password I'm not comfortable putting it in public
flashrom dropped tasmota-sensors on it happily, but that's not much use in terms of decoding the sensors
I found no direct message functionality on github, you can send me at [email protected]
I managed to dump my firmware if someone is interested
@Hakon yes please. Could you publicly share?
Most helpful comment
The slight downside with factory re-provisioning w/ cloud is that everyone listening can determine what your device id and pkey are now. (I'm not sure if there are nefarious things you can do if you know a particular device's pkey, like reset wifi credentials [knocking it offline] or maybe worst case, some OTA update)
The other option is to dump the flash of existing unit and you can get your id/key.
d: (E30014FFdddddddddddddddddddd)I have an example python script which will take this device token, listen to the mqtt topic, parse, and print out the sensor data. No need for app:
https://gist.github.com/zerog2k/b3afcaf3ff92a60474a159c7044dc8ce
however, the data only as good as this device/cloud, i put it side by side with a Nordic Thingy (which also outputs TVOC, eCO2, etc) which seems to be slightly different on a few values, and not sure about the eCO2 and TVOC... (I think I would trust the Nordic design/quality better ;)