Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 15:46 18 Apr 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Cheap Thermostat

Author Message
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 09:36pm 05 Jan 2021
Copy link to clipboard 
Print this post

Has anyone seen These

Cheap less than $4 bluetooth temp and humidity sensors that can have custom firmware installed
Web firmware flashing page
I ordered 5 and they were here within a week
Just flashed one tonight with the new firmware but I'm not even going to try and figure out how to get bluetooth working and decoding it
I'm using them as cheap temp sensors but I'm sure someone knowledgeable here could do something with them
Unless they aren't worth the money
 
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 367
Posted: 09:30am 06 Jan 2021
Copy link to clipboard 
Print this post

Remote sensors for the CMM2 -- there's an idea.

Where did you buy yours from (UK)?

Nim
Entropy is not what it used to be
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 01:45pm 06 Jan 2021
Copy link to clipboard 
Print this post

  Nimue said  Remote sensors for the CMM2 -- there's an idea.

Where did you buy yours from (UK)?

Nim

Took me ages to find the email
I got them here Gearbest in China

An exampl;e script to get the bluetooth data from the thermometer
#!/usr/bin/env python3
import sys
from datetime import datetime
import bluetooth._bluetooth as bluez

from bluetooth_utils import (toggle_device, enable_le_scan,
                            parse_le_advertising_events,
                            disable_le_scan, raw_packet_to_str)

# Use 0 for hci0
dev_id = 0
toggle_device(dev_id, True)

try:
   sock = bluez.hci_open_dev(dev_id)
except:
   print("Cannot open bluetooth device %i" % dev_id)
   raise

# Set filter to "True" to see only one packet per device
enable_le_scan(sock, filter_duplicates=False)

try:
   def le_advertise_packet_handler(mac, adv_type, data, rssi):
       data_str = raw_packet_to_str(data)
       # Check for ATC preamble
       if data_str[6:10] == '1a18':
           temp = int(data_str[22:26], 16) / 10
           hum = int(data_str[26:28], 16)
           batt = int(data_str[28:30], 16)
           print("%s - Device: %s Temp: %sc Humidity: %s%% Batt: %s%%" % \
                (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), mac, temp, hum, batt))

   # Called on new LE packet
   parse_le_advertising_events(sock,
                               handler=le_advertise_packet_handler,
                               debug=False)
# Scan until Ctrl-C
except KeyboardInterrupt:
   disable_le_scan(sock)


Yes I know it's in Python not MM but it came from hackaday.com/2020/12/08/exploring-custom-firmware-on-xiaomi-thermometers/
Edited 2021-01-06 23:51 by lew247
 
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 367
Posted: 02:40pm 06 Jan 2021
Copy link to clipboard 
Print this post

Thank you -- happy with a bit of Big P ;-)

Bought.....

Worth a "fiddle" and nice to introduce to schools to remote sensing and Python.

Q:  Is there a bluetooth implementation for CMM2 / MMBasic?

Nim
Edited 2021-01-07 00:44 by Nimue
Entropy is not what it used to be
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 532
Posted: 03:01pm 06 Jan 2021
Copy link to clipboard 
Print this post

I have ordered it here
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 03:12pm 06 Jan 2021
Copy link to clipboard 
Print this post

  Nimue said  Thank you -- happy with a bit of Big P ;-)
Nim

I wish I could say the same, there's so much more I could do but it's too advanced for me
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 5878
Posted: 08:02pm 06 Jan 2021
Copy link to clipboard 
Print this post

  Nimue said  
Q:  Is there a bluetooth implementation for CMM2 / MMBasic?

Nim

I did have a play with the HC-05 and HC-06 Bluetooth modules but it was a while ago.
They are serial to Bluetooth so easy enough to drive from MMBasic.
I will have to dust off the modules (and the brain).

Jim
VK7JH
MMedit   MMBasic Help
 
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 367
Posted: 09:59am 08 Jan 2021
Copy link to clipboard 
Print this post

Having obtained these and flashed the custom rom (easy) I can confirm that the bluetooth low energy implementation seems to not be compatible with Python 3.9 running on Windows 10 (a Python issue).

Apparently it works fine on Linux (not my OS of choice).

I'll keep plugging away.

Nim
Entropy is not what it used to be
 
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 367
Posted: 11:06am 08 Jan 2021
Copy link to clipboard 
Print this post

Some progress....

The "Bleak" library :  https://bleak.readthedocs.io/en/latest/scanning.html works for reading the advertised bluetooth data...  with one caveat..... not under Anaconda / Jupyter notebooks.

So, under Windows 10 with the above libraries, I am able to "see" the sensior:

In the screenshot, the device is "ATC_E1815F" and the next couple of lines is the packet info for the data being sent.




Need to "park" this and do some paying work for a bit....

Nim
Entropy is not what it used to be
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 532
Posted: 11:49am 08 Jan 2021
Copy link to clipboard 
Print this post

It will be nice to find it with ESP32 and then connect it to CMM2 (serial, SPI or IIC).

I'm still waiting for my sensors...  
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
TheFRB
Newbie

Joined: 03/04/2021
Location: United States
Posts: 3
Posted: 01:16am 04 Apr 2021
Copy link to clipboard 
Print this post

If anyone's still interested in these thermometers I can give some information. I've done two installations using them: one at my house and one at a friend's greenhouse. Some high level details about what I did:

1) Flashed the custom firmware found at https://github.com/atc1441/ATC_MiThermometer (not necessary, but unless you want to stay in the Xiaomi ecosystem its better to use to the custom firmware).
2) Have a Raspberry Pi Zero W reading the BLE advertising data (the thermometers broadcast temperature, humidity and battery status every 5 or 6 seconds, no need to pair)
3) Pushing this data to an MQTT broker running on another machine (RPi 3) over TCP/IP (wireless)
4) On the same RPi 3 I'm running InfluxDB and Grafana that ingest this data via MQTT subscripitons.

I did something similar for my friend's greenhouse -- 6 thermometers (5 in the greenhouse in different zones, 1 outside as reference), but added LoRa to the mix (Long Range / Low Bandwidth wireless) since the greenhouse is a good 50 / 60 yards from his house. The only difference is the RPiZero pushes the thermometer data across LoRa (its a serial connection) via a LoRa hat. The other machine also has a LoRa hat (both Waveshare SX1268s, ~$25 apiece) from which it receives the data, then pushes to the MQTT broker.

Phase 2 at his greenhouse is to start adding some automation (i.e. turn on fans to circulate air if the differential between zones hits a certain metrics, etc.) I'm looking at some bluetooth controlled relays that we can plug the fans into.

If anyone has any questions I'll gladly answer them.
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3008
Posted: 01:26am 04 Apr 2021
Copy link to clipboard 
Print this post

Thanks for the info. I got a couple, but haven't played yet.

Can you provide a little more information about item 2) -- unpaired bluetooth reception?
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
TheFRB
Newbie

Joined: 03/04/2021
Location: United States
Posts: 3
Posted: 01:58am 04 Apr 2021
Copy link to clipboard 
Print this post

The thermometers will broadcast what's called a BLE advertising packet (what Apple calls iBeacon). You don't have to be paired to read the data; you just 'pluck' it out of the air. I'm using Python on the PiZeroW (which has really good bluetooth reception). There is a python package called "Bleak" that I have been using to grab and parse this data (https://pypi.org/project/bleak/).

One thing of note about the firmware that comes with the thermometer: this advertising data is encrypted. You cannot extract any info out of it without a key. The webpage I discussed about the custom firmware (https://github.com/atc1441/ATC_MiThermometer) has a tool that will generate that key for you. However, if you flash the new custom firmware the broadcast message isn't encrypted. Another good reason to flash the custom firmware.

I believe (because I personally haven't tried it), even if you're on the original firmware if you pair/connect with the thermometer you can read the data, no problem. But pairing/connecting will actually drain your battery a little faster than just passively reading. For me, its just easier to read the advertising packets (I don't have to code anything re: connecting to each thermometer).

The ATC_MiTHermometer site has really good information about how the data is stored in the packet. You have to convert stuff from hex to decimal, but its pretty easy to figure out once you understand it.
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3008
Posted: 02:08am 04 Apr 2021
Copy link to clipboard 
Print this post

Ok. Good to know. Thanks.
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
TheFRB
Newbie

Joined: 03/04/2021
Location: United States
Posts: 3
Posted: 02:23am 04 Apr 2021
Copy link to clipboard 
Print this post

  lew247 said  
  Nimue said  Remote sensors for the CMM2 -- there's an idea.

Where did you buy yours from (UK)?

Nim

Took me ages to find the email
I got them here Gearbest in China

An exampl;e script to get the bluetooth data from the thermometer


{SNIP}

try:
   def le_advertise_packet_handler(mac, adv_type, data, rssi):
       data_str = raw_packet_to_str(data)
       # Check for ATC preamble
       if data_str[6:10] == '1a18':
           temp = int(data_str[22:26], 16) / 10
           hum = int(data_str[26:28], 16)
           batt = int(data_str[28:30], 16)
           print("%s - Device: %s Temp: %sc Humidity: %s%% Batt: %s%%" % \
                (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), mac, temp, hum, batt))

{SNIP}


Yes I know it's in Python not MM but it came from hackaday.com/2020/12/08/exploring-custom-firmware-on-xiaomi-thermometers/


A quick note on this code. It was the basis for the first revision of my system and the temperature calculation isn't quite correct. The temperature (which is always reported in C, even if you configure the screen to show F) is stored as tenths of a degree in an INT16, but its a signed INT16, i.e. the first bit represents the sign, and, if a negative number, the bits are inverted. The above code assumes its an unsigned INT16, so things go a bit haywire when the temperature drops below zero. For instance, at -1C (which would be passed as -10) the hex representation you get in the BLE packet is 0xFFF6, which as an unsigned INT16 is 65526 (or 6552.6 C).

When I hit the first cold snap my data looked really, really funky.
 
Tinine
Guru

Joined: 30/03/2016
Location: United Kingdom
Posts: 1646
Posted: 03:01pm 04 Apr 2021
Copy link to clipboard 
Print this post

If you would like to use these devices on an Android phone/tablet, the attached "GrauBasic" makes it really simple.

Just remove ".zip" from the file name and allow your device to accept an app from "other sources" (developer options).

BLE sample programs are included.


GRAU BASIC!_2.01_de.grauonline.basic_2010.apk.zip
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 5878
Posted: 08:23am 06 Apr 2021
Copy link to clipboard 
Print this post

Reading the thermometers with MMBasic and a ESP32 is easy.
Change the com port setting to suit your setup.

 ' ESP32 BLE logger
 ' TassyJim April 2021
 OPTION EXPLICIT
 OPTION DEFAULT INTEGER
 ' Global variables
 CONST qt$=CHR$(34)
 CONST crlf$=CHR$(13)+CHR$(10)
 '
 dim string comPort$ = "com1:921600,1024" '"com1:115200,1024"
 dim float temperature, humidity, batpc, batV
 dim inTxt$, ink$
 dim integer quit, CMM2, x, Verbose = 0, showDebug
 
 OPEN comPort$ AS #1
 PAUSE 2000 'wait for ESP32 to wake up afer power on
 CLOSE #1 'clear the buffer
 OPEN comPort$ AS #1
 
 IF instr(MM.DEVICE$,"Colour Maximite 2") THEN
   CMM2 = 1
 ELSE
   CMM2 = 0
 ENDIF
 
 ESPcommand("AT") ' test ESP for responce
 IF OK()THEN
   PRINT "ESP alive!"
 ELSE
   PAUSE 200
   ESPcommand("AT")
   IF OK()THEN
     PRINT "ESP alive!"
   ELSE
     PRINT inTxt$
   ENDIF
 ENDIF
 
 pause 500
 getinput
 ESPcommand("AT+CWMODE=0")
 if not OK() then print "Error 1"
 ESPcommand("AT+BLEINIT=1")
 if not OK() then print "Error 2"
 ESPcommand("AT+BLESCANPARAM?")
 if not OK() then print "Error 3"
 ESPcommand("AT+BLESCAN=1,0")
 
 DO
   ink$ = INKEY$
   SELECT CASE ink$
     CASE CHR$(27),"Q","q"
       quit = 1
     CASE "D","d"
       showDebug = 1 - showDebug
       IF showDebug THEN PRINT "Debug on" ELSE PRINT "Debug off"
     CASE "V","v"
       verbose = 1 - verbose
       
   END SELECT
   '
   x = waitFor(30000,250,crlf$)
   if x = 1 then ' we have a crlf pair
     decode inTxt$
   endif
 LOOP UNTIL quit = 1
 
 PRINT "Shutting down..."
 ESPcommand "AT+BLESCAN=0"
 if not OK() then print "Error shutting down"
END
 '
 
 'send ESP related command
SUB ESPcommand(txt$)
 getInput
 PRINT #1,txt$+crlf$;
 IF showDebug THEN PRINT txt$ 'DEBUG
END SUB
 
sub getInput
 IF LOC(#1) > 0 THEN
   do
     inTxt$=INPUT$(255,#1)
     if verbose then print inTxt$
   loop until LOC(#1)=0
 ENDIF
 
END sub
 
 ' wait timeout% mS or 250 bytes for "OK"
FUNCTION OK(timeout%)
 IF timeout% = 0 THEN timeout% = 500
 IF waitFor(timeout%,250,"OK") = 1 THEN OK = 1
END FUNCTION
 
 ' wait for text string(s). tested in supplied order and stops after first blank text
 ' returns index to found txt or 0 if timeout
 ' if maxlen is non zero, function will return 255 if max len is reached
 ' and global variable inTxt$ will contain the received text.
FUNCTION waitFor(timeout%,maxlen%,a1$,a2$,a3$,a4$,a5$,a6$) AS INTEGER
 LOCAL INTEGER n, c, endTime = TIMER + timeout%
 LOCAL a$
 DO
   IF LOC(#1) THEN
     a$ = a$ + INPUT$(1,#1)
     INC c
     IF c >= maxlen% THEN n = 255 : EXIT DO
     IF RIGHT$(a$,LEN(a1$)) = a1$ THEN n = 1 : EXIT DO
     IF a2$="" THEN CONTINUE DO
     IF RIGHT$(a$,LEN(a2$)) = a2$ THEN n = 2 : EXIT DO
     IF a3$="" THEN CONTINUE DO
     IF RIGHT$(a$,LEN(a3$)) = a3$ THEN n = 3 : EXIT DO
     IF a4$="" THEN CONTINUE DO
     IF RIGHT$(a$,LEN(a4$)) = a4$ THEN n = 4 : EXIT DO
     IF a5$="" THEN CONTINUE DO
     IF RIGHT$(a$,LEN(a5$)) = a5$ THEN n = 5 : EXIT DO
     IF a6$="" THEN CONTINUE DO
     IF RIGHT$(a$,LEN(a6$)) = a6$ THEN n = 6 : EXIT DO
   ENDIF
 LOOP UNTIL TIMER > endtime OR c > 254
 IF maxlen% THEN inTxt$ = a$
 waitFor = n
END FUNCTION
 
sub decode txt$
 local integer startTxt
 local adv_data$, fld$
 startTxt = instr(txt$,"BLESCAN")
 if startTxt then
   txt$ = mid$(txt$,starttxt+8)
   adv_data$ = field$(txt$,3,",")
   if verbose then print adv_data$
   fld$ = mid$(adv_data$,5,4)
   if fld$ = "1a18" then ' we have the correct data
     fld$ = mid$(adv_data$,9,12)
     print "MAC address: ";fld$
     fld$ = mid$(adv_data$,21,4) ': print fld$
     temperature = signed16(val("&h"+fld$))
     temperature = temperature/10
     fld$ = mid$(adv_data$,25,2)': print fld$
     humidity =  val("&h"+fld$)
     fld$ = mid$(adv_data$,27,2)': print fld$
     batpc =  val("&h"+fld$)
     fld$ = mid$(adv_data$,29,4)': print fld$
     batV =  val("&h"+fld$)/1000
     
     print Time$;"  ";temperature;"`C ";Humidity;"% ";batpc;"% ";batV;"V "
     print
   endif
 endif
end sub
 
function signed16(x)
 if x > 32767 then
   signed16 = x - 65536
 else
   signed16 = x
 endif
end function


Output:
  Quote  MAC address: a4c1382865be
18:13:27   23.9`C  52%  79%  2.919V

MAC address: a4c1382865be
18:13:48   23.9`C  52%  79%  2.919V


This is with the standard ESP32 firmware and module firmware from the first post.

Jim
Edited 2021-04-06 18:25 by TassyJim
VK7JH
MMedit   MMBasic Help
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 5878
Posted: 04:09am 07 Apr 2021
Copy link to clipboard 
Print this post

This version is a bit tidier.
It should run on any of the 'mites

V to toggle verbose mode and Q or esc to quit.

 ' ESP32 BLE logger
 ' TassyJim April 2021
 OPTION EXPLICIT
 OPTION DEFAULT INTEGER
 ' Global variables
 CONST qt$=CHR$(34)
 CONST crlf$=CHR$(13)+CHR$(10)
 '
 DIM STRING comPort$ = "com1:921600,2048" '"com1:115200,2048"
 DIM FLOAT temperature, humidity, batpc, batV, counter
 DIM inTxt$, ink$, j$, MACadr$
 DIM INTEGER quit, Verbose = 1
 
 OPEN comPort$ AS #1
 PAUSE 2000 'wait for ESP32 to wake up afer power on
 CLOSE #1 'clear the buffer
 OPEN comPort$ AS #1

 ESPcommand("AT") ' test ESP for responce
 IF OK()THEN
   PRINT "ESP alive!"
 ELSE
   PAUSE 200
   ESPcommand("AT")
   IF OK()THEN
     PRINT "ESP alive!!"
   ELSE
     PRINT inTxt$
   ENDIF
 ENDIF
 
 DO ' flush the comms buffer
   j$ = INPUT$(255,#1)
   IF verbose THEN PRINT j$
 LOOP UNTIL j$ = ""
 
 ESPcommand("AT+CWMODE=0")
 IF NOT OK() THEN PRINT "Error 1"
 ESPcommand("AT+BLEINIT=1")
 IF NOT OK() THEN PRINT "Error 2"
 ESPcommand("AT+BLESCANPARAM?")
 IF NOT OK() THEN PRINT "Error 3"
 IF verbose THEN PRINT inTxt$
 ESPcommand("AT+BLESCAN=1,0")
 IF verbose THEN PRINT "Scanning..."
 
 DO
   ink$ = INKEY$
   SELECT CASE ink$
     CASE CHR$(27),"Q","q"
       quit = 1
     CASE "V","v"
       verbose = 1 - verbose
       
   END SELECT
   IF LOC(#1) THEN getInput
   '
 LOOP UNTIL quit = 1
 
 PRINT "Shutting down..."
 ESPcommand "AT+BLESCAN=0"
 IF NOT OK() THEN PRINT "Error shutting down"
 CLOSE #1
END
 '
 
 'send ESP related command
SUB ESPcommand(txt$)
 PRINT #1,txt$+crlf$;
 IF verbose THEN PRINT txt$
END SUB
 
SUB getInput
 LOCAL INTEGER x
   x = waitfor(500,crlf$)
   IF verbose THEN PRINT inTxt$;
   IF x = 1 THEN
     decode inTxt$
   ENDIF
END SUB
 
 ' wait timeout% mS or 250 bytes for "OK"
FUNCTION OK(timeout%)
 IF timeout% = 0 THEN timeout% = 500
 IF waitFor(timeout%,"OK"+crlf$) = 1 THEN
 OK = 1
 IF verbose THEN PRINT "OK"
 ENDIF
END FUNCTION
 
 ' wait for text string.
 ' returns 1 for end match, 255 if 250 characters reached  or 0 if timeout
 ' global variable inTxt$ will contain the received text.
FUNCTION waitFor(timeout%,a1$) AS INTEGER
 LOCAL INTEGER n, c, endTime = TIMER + timeout%
 LOCAL a$
 DO
   IF LOC(#1) THEN
     a$ = a$ + INPUT$(1,#1)
     'if verbose then print right$(a$,1);
     c = c + 1
     IF c >= 250 THEN n = 255 : EXIT DO
     IF RIGHT$(a$,LEN(a1$)) = a1$ THEN n = 1 : EXIT DO
   ENDIF
 LOOP UNTIL TIMER > endtime
 IF n THEN inTxt$ = a$
 waitFor = n
END FUNCTION
 
SUB decode txt$
 LOCAL INTEGER startTxt
 LOCAL adv_data$, fld$
 startTxt = INSTR(txt$,"BLESCAN")
 IF startTxt THEN
   txt$ = MID$(txt$,starttxt+8)
   adv_data$ = FIELD$(txt$,3,",")
   'if verbose then print adv_data$
   fld$ = MID$(adv_data$,5,4)
   IF fld$ = "1a18" THEN ' we have the correct data
     MACadr$ = MID$(adv_data$,9,12)
     fld$ = MID$(adv_data$,21,4) ': print fld$
     temperature = signed16(VAL("&h"+fld$))
     temperature = temperature/10
     fld$ = MID$(adv_data$,25,2)': print fld$
     humidity =  VAL("&h"+fld$)
     fld$ = MID$(adv_data$,27,2)': print fld$
     batpc =  VAL("&h"+fld$)
     fld$ = MID$(adv_data$,29,4)': print fld$
     batV =  VAL("&h"+fld$)/1000
     fld$ = MID$(adv_data$,33,2)': print fld$
     counter =  VAL("&h"+fld$)
     PRINT TIME$;"  ";MACadr$;"  ";temperature;"`C ";Humidity;"%rh ";batpc;"% ";batV;"V ";counter
     PRINT
   ENDIF
 ENDIF
END SUB
 
FUNCTION signed16(x%) AS INTEGER
 IF x% > 32767 THEN
   signed16 = x% - 65536
 ELSE
   signed16 = x%
 ENDIF
END FUNCTION


Jim
VK7JH
MMedit   MMBasic Help
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024