There is a new inexpensive Temperature and humidity sensor by xiaomi.
This time is no longer round ,
if you like me would like to get the temperature and humidity data from time to time to import in a graphing tool like grafana, there is a simple solution using classic bash tools and gatttool.
First you have to indentify the mac-address of your little sensor, for this , just make sure the sensor is in range of your linux device ans launch a
hcitool lescann
this command will spit out all the bluetooth devices in range
just find the line with the name of the device and copy the mac address A4:C1:38:8C:77:CA LYWSD03MMC
then you must start a little bash script like this :
#!/bin/bash
bt=$(timeout 15 gatttool -b A4:C1:38:8C:77:CA --char-write-req --handle='0x0038' --value="0100" --listen)
if [ -z "$bt" ]
then
echo "The reading failed"
else
echo "Got data"
echo $bt temphexa=$(echo $bt | awk -F ' ' '{print $12$11}'| tr [:lower:] [:upper:] ) humhexa=$(echo $bt | awk -F ' ' '{print $13}'| tr [:lower:] [:upper:])
temperature100=$(echo "ibase=16; $temphexa" | bc)
humidity=$(echo "ibase=16; $humhexa" | bc)
echo "scale=2;$temperature100/100"|bc
echo $humidity
fi
this is a skeleton that you can improve , but for now it pretty much work like that ,
first it use gatttol to connect to the sensor and listen for 15 sec
During these fifteen seconds , you can be pretty much sure to receive at least some data like this :
Characteristic value was written successfully Notification handle = 0x0036 value: 58 03 47 a0 0b Notification handle = 0x0036 value: 55 03 47 a0 0b
this tell me that during the 15 sec of connection i received the information that i need two times.
what i’m after are the value 58 03 for the temperature , and 47 for the humidity.
the temperature is little endian format its mean that the two group must be inverted before decoding the data. i invert the values with awk and decode them using bc.
bc doesn’t like when the hex values are not capitalised so tr is used to do that.
bc then give you the temperature multiplied by 100. relaunch bc to divice per 100,
For the humidity its simpler , you get the value in one step without inverting anyting
Then you can do what you need with theses two vars , insert then in some database etc ..
there is room from improvement: for example this script is not capable of decoding negative temperature.
i will post an improved version when i figure out how to do it
GREAT.. perhaps you can do a hass integration for this… ?!
Sorry , but i don’t know what’s Hass , and google is not helping…
I am getting a syntax error at line 11 – unmatched ‘ character – any ideas on how to correct this?
I removed the extra ‘ character and have made some other changes and it is working well for me , thankyou.
Andrew, could you paste your script?
i edited the script and removed the quote on line 11
Here is my try on this. I wonder if the extra bytes are battery voltage (mV). Works with negative temperature values, tested from -25C up to + 25C.
-20.30 69 2.815 [12 f8 45 ff 0a]
-1.10 82 2.815 [92 ff 52 ff 0a]
-0.77 82 2.815 [b3 ff 52 ff 0a]
-0.46 81 2.815 [d2 ff 51 ff 0a]
-0.18 81 2.815 [ee ff 51 ff 0a]
0.11 80 2.815 [0b 00 50 ff 0a]
0.39 80 2.815 [27 00 50 ff 0a]
0.66 80 2.815 [42 00 50 ff 0a]
0.92 79 2.815 [5c 00 4f ff 0a]
1.25 79 2.815 [7d 00 4f ff 0a]
21.34 51 2.815 [56 08 33 ff 0a]
8< – – – 8< – – – 8< – – – 8< – – – 8 “-0.05” and “.05” -> “0.05”
temperature=$(echo “scale=2; $temperature100 / 100” | bc | sed ‘s:^\(-\?\)\.\(.*\)$:\10.\2:’)
battery=$(echo “scale=3; $battery1000 / 1000” | bc)
echo $temperature $humidity $battery “[$hexa]”
fi
(second try, sorry. Half of the message disappeared(?) after “Submit”)
Here is my try on this. I wonder if the extra bytes are battery voltage (mV). Works with negative temperature values, tested from -25C up to + 25C.
-20.30 69 2.815 [12 f8 45 ff 0a]
-1.10 82 2.815 [92 ff 52 ff 0a]
-0.77 82 2.815 [b3 ff 52 ff 0a]
-0.46 81 2.815 [d2 ff 51 ff 0a]
-0.18 81 2.815 [ee ff 51 ff 0a]
0.11 80 2.815 [0b 00 50 ff 0a]
0.39 80 2.815 [27 00 50 ff 0a]
0.66 80 2.815 [42 00 50 ff 0a]
0.92 79 2.815 [5c 00 4f ff 0a]
1.25 79 2.815 [7d 00 4f ff 0a]
21.34 51 2.815 [56 08 33 ff 0a]
#!/bin/bash
bt=$(timeout 25 gatttool -b A4:C1:38:53:C7:B2 –char-write-req –handle=0x0038 –value=0100 –listen | grep “Notification handle” -m 1)
if [ -z “$bt” ]
then
echo “The reading failed”
else
#echo “Got data”
hexa=$(echo $bt | awk ‘{print $6 ” ” $7 ” ” $8 ” ” $9 ” ” $10}’)
temphexa=$(echo $bt | awk ‘{print $7$6}’ | tr ‘[:lower:]’ ‘[:upper:]’)
humhexa=$(echo $bt | awk ‘{print $8}’ | tr ‘[:lower:]’ ‘[:upper:]’)
batthexa=$(echo $bt | awk ‘{print $10$9}’ | tr ‘[:lower:]’ ‘[:upper:]’)
temperature100=$(echo “ibase=16; $temphexa” | bc)
humidity=$(echo “ibase=16; $humhexa” | bc)
battery1000=$(echo “ibase=16; $batthexa” | bc)
if [ $temperature100 -gt 32767 ]; then
temperature100=$(($temperature100 – 65536))
fi
# Add missing leading zero if needed (sed): “-.05” -> “-0.05” and “.05” -> “0.05”
temperature=$(echo “scale=2; $temperature100 / 100” | bc | sed ‘s:^\(-\?\)\.\(.*\)$:\10.\2:’)
battery=$(echo “scale=3; $battery1000 / 1000” | bc)
echo $temperature $humidity $battery “[$hexa]”
fi
How long does the CR2032 battery in this model lasts, with readings every 15s?
Battery level it is reported in hex on UUID 0x2a19 (got it from nRFConnect on Android)
gatttool -b $mac –char-read –uuid 0x2a19 –listen
handle: 0x001b value: 63
#convert it to dec. In my case is 99%
gatttool -b $mac –char-read –uuid 0x2a19 | awk ‘{print “ibase=16;”, $4}’ | bc
99
Tried on other devices and always reporting 99%
So, just forget this approach.
# Device Name
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A00′ | tr -d [:space:] | xxd -r -p -s19
# LYWSD03MMC
# Battery Level
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2a19′ | tr [:lower:] [:upper:] | tr -d [:space:] | tail -c -2 | echo “ibase=16; $(cat -)” | bc
# 99
# Model Number String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A24′ | tr -d [:space:] | xxd -r -p -s19
# LYWSD03MMC
# Serial Number String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A25′ | tr -d [:space:] | xxd -r -p -s19
# XX.X-XXX-XX-XXXXX-
# Firmware Revision String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A26′ | tr -d [:space:] | xxd -r -p -s19
# 1.0.0_0109
# Hardware Revision String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A27′ | tr -d [:space:] | xxd -r -p -s19
# B1.4
# Software Revision String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A28′ | tr -d [:space:] | xxd -r -p -s19
# 0109
# Manufacturer Name String
gatttool -b XX:XX:XX:XX:XX:XX –char-read –uuid=’0x2A29′ | tr -d [:space:] | xxd -r -p -s19
# miaomiaoce.com
Thank you!!1
I understand how you get this: A4:C1:38:8C:77:CA LYWSD03MMC
But you didn’t explain how you got this: –handle=’0x0038′
Where does the handle come from? Trial and error?
I’m using slightly modiefied script for reading multiple sensors on raspberry zeroW:
#!/bin/bash
Sensor1=A4:C1:38:88:D3:2E
Sensor2=A4:C1:38:52:5A:26
Sensor3=A4:C1:38:36:3E:D1
Sensor1name=Bedroom
Sensor2name=Anopinperse
Sensor3name=Fridge
readsensor () {
bt=$(sleep 1;timeout 15 gatttool -b $Sensor –char-write-req –handle=’0x0038′ ->
}
result () {
while [[ “$bt” =~ .*error*. ]]; do
readsensor
done
humhexa=$(echo $bt | awk -F ‘ ‘ ‘{print $13}’| tr [:lower:] [:upper:])
humidity=$(echo “ibase=16; $humhexa” | bc)
while [[ “$humidity” -gt 101 || -z “$humidity” ]];do
readsensor
done
}
printsensor () {
temphexa=$(echo $bt | awk -F ‘ ‘ ‘{print $12$11}’| tr [:lower:] [:upper:] )
humhexa=$(echo $bt | awk -F ‘ ‘ ‘{print $13}’| tr [:lower:] [:upper:])
temperature100=$(echo “ibase=16; $temphexa” | bc)
humidity=$(echo “ibase=16; $humhexa” | bc)
echo -n “$Sensorname Temperature: ”
echo “scale=2;$temperature100/100″|bc
echo -n “$Sensorname Humidity: ”
echo $humidity
echo “”
}
Sensor=$(echo $Sensor1)
Sensorname=$(echo $Sensor1name)
readsensor
result
printsensor
Sensor=$(echo $Sensor2)
Sensorname=$(echo $Sensor2name)
readsensor
result
printsensor
Sensor=$(echo $Sensor3)
Sensorname=$(echo $Sensor3name)
readsensor
result
printsensor
good job !
i found it there : https://github.com/belkop-ghb/LYWSD03MMC/blob/master/writeToMqtt.sh
The original script only works as intended at positive temperatures. LYWSD03MMC can handle negative values down to -9.9 °C. The easy solution is to only use the hex values and let a C program do the rest.
By the way, even after 9 months in a humid environment, the sensor boards show no signs of deterioration. Only the battery loses its capacity very quickly at temperatures below 10 degrees.
Her’s my script:
# struct sensor_data {
# char mac_addr[18];
# char temp[5];
# char hum[3];
# char batt[5];
# } xdata;
#define array
SENSORS=(tinker#a4:C1:38:B4:59:4C
nixda#aa:bb:38:b4:e9:4f)
RSLT=”tmpfile”
touch $RSLT
# poll sensors
for ITEM in “${SENSORS[@]}” ; do
NAME=”${ITEM%%#*}”
MAC_ADDRESS=”${ITEM##*#}”
# collect sensor data
DATA=$(timeout 15 gatttool -t public -b $MAC_ADDRESS –char-write-req –handle=’0x0038′ –value=”0100″ –listen | grep “Notification handle” -m 1)
DATUM=`date +%y-%m-%d\ %H:%M:%S` # get data collection time
if [ -z “$DATA” ]
then # reading failed
# Clear sensor structure data
TEMP=’0000′ # 0 is a valid result!
HUM=’00’ # 0 is not a valid result
BATT=’0000′ # 0 is not a valid result
# log read error
printf “$MAC_ADDRESS\t$DATUM\tBT fail [2]\n” >> xfail.log
else # got data
TEMP=$(echo $DATA | awk -F ‘ ‘ ‘{print $7$6}’)
HUM=$(echo $DATA | awk -F ‘ ‘ ‘{print $8}’)
BATT=$(echo $DATA | awk -F ‘ ‘ ‘{print $10$9}’)
fi
printf “$MAC_ADDRESS\x00” >> $RSLT
printf “$TEMP\x00” >> $RSLT
printf “$HUM\x00” >> $RSLT
printf “$BATT\x00” >> $RSLT
done
mv $RSLT rsltfile
The rsltfile is all ASCII. Simply read it and print data in c, phyton, whatever.
Hello. I’m trying to make It work on a Rapsberry pi 4 Model B running openhabian.5.10.63.
I detect the MAC , but gatttool always returns me:
connect to A4:C1:38:BA:D5:35: Connection refused (111)
Any idea? Thank you!
i was just searcing for these things thanks for posting them Xiaomi is a good product hope to see new models in the coming time thanks for updating