Read actual vales from the BeeWi BBW200 - Smart Clim


7 posts
by vekfra » Sat Mar 12, 2016 5:55 pm
I recently purchased some BeeWi equipment from ibood (one time offer) and wanted to handle it in OpenHab.
. 2 Smart Tracker BBD100-A10
. 2 Smart Temperature & Humidity Sensor BBW200-A1
. 1 Smart LED Color Bulb BBL227-A1

As there is no binding for BeeWi I started with the beewibulb script from Stephanie Maks https://www.raspberrypi.org/forums/viewtopic.php?f=37&t=117729 with the update from Gerrit Hannaert and got that running.
Next I wanted to get the information from the BeeWi 'BBW200 - Smart Temperature & Humidity Sensor'

This script reads the actual temperature, humidity, battery status and the device information. The historical data is not handled yet.
Future step would be to create a rule in OpenHab using the knowledge gathered.

Some output of the script:
Code: Select all
pi@raspberrypi:~ $ sudo ./beewiclim.py         
Correct usage is "[sudo] beewiclim.py <device address> <command> [hci device]"
       <device address> in the format XX:XX:XX:XX:XX:XX
       Commands:  stat          - Get status
       Commands:  val           - Get values (temperature, humidity, battery)
       Commands:  raw           - Get values (temperature, humidity, battery)
       [hci device] i.e. hci1 in case of multiple devices
Code: Select all
pi@raspberrypi:~ $ sudo ./beewiclim.py 5C:31:3E:XX:XX:XX' stat
-------------------------------------
Device name       = BeeWi SmartClim 1
Model number      = BeeWi BBW200
Serial number     =
Firmware revision = V1.5 R140514
Hardware revision = 1.0
Software revision =
Manufacturer       = Voxland
-------------------------------------
Temperature       = 19.5℃
Humidity          = 25%
Battery           = 97%
-------------------------------------
Code: Select all
pi@raspberrypi:~ $ sudo ./beewiclim.py 5C:31:3E:XX:XX:XX' val
-------------------------------------
Temperature       = 19.5℃
Humidity          = 25%
Battery           = 97%
-------------------------------------
Code: Select all
pi@raspberrypi:~ $ sudo ./beewiclim.py 5C:31:3E:XX:XX:XX' raw
19.5 25 97


The full Python script:
Code: Select all
#!/usr/bin/env python2.7

#   A python script to read actual vales from the BeeWi 'BBW200 - Smart Temperature & Humidity Sensor'
#   BeeWi website: http://www.bee-wi.com/en.cfm
#
#   Missing: Read the historical temperature & humidity data (0x0039)
#
#   Tested on elelentary OS elementary OS 0.3.2 Freya >> BLE hardware: Broadcom Corp. BCM2045B (BDC-2.1) USB dongle
#   Tested on Raspberry 3
#
#   Don't kill me for the source, it's the first time I did something in Python.
#
#
#   Script based on the beewibulb.py script by Stephanie Maks >> Controlling a BeeWi SmartLite
#     https://www.raspberrypi.org/forums/viewtopic.php?f=37&t=117729
#     Used the modicications of Gerrit Hannaert
#
#   Some fiddling with the bluetooth packet capture on Android, Wireshark, hcitool, hciconfig, GATTTool, apktool and testing, testing, testing.....

#   Many thanks to Stephanie Maks & Gerrit Hannaert
#   
#   Stephanie Maks figured out with help from -- and thanks to -- the following sources:
#      http://stackoverflow.com/questions/24853597/ble-gatttool-cannot-connect-even-though-device-is-discoverable-with-hcitool-lesc
#      http://mike.saunby.net/2013/04/raspberry-pi-and-ti-cc2541-sensortag.html
#      https://github.com/sandeepmistry/node-yeelight-blue
#      https://www.nowsecure.com/blog/2014/02/07/bluetooth-packet-capture-on-android-4-4/
#
#   note: this needs to be called with 'sudo' or by root in order to work with some of the hci commands

import os
import sys
from subprocess import call, check_output
import time

def cycleHCI(s_hci) :
   # maybe a useless time waster but it makes sure our hci is starting fresh and clean
   # nope in fact we need to call this before each time we do hci or gatt stuff or it doesn't work
   call(['hciconfig', 's_hci', 'down'])
   time.sleep(0.1)
   call(['hciconfig', 's_hci', 'up'])
   time.sleep(0.1)

def getResultStringForDeviceMacHandle(s_hci, s_mac, s_handle) :
   # Read the string from handle
   raw_input = check_output(['gatttool', '-i', s_hci, '-b', s_mac, '--char-read', '--handle='+s_handle]);
   result_string = ''
   if ':' in raw_input:
      raw_list=raw_input.split(':')
      raw_data=raw_list[1]
      raw_data=raw_data.strip()
      octet_list=raw_data.split(' ')
      for octet in octet_list :
         j = int(octet, 16)
         if j > 31 and j < 127 : result_string += str(unichr(j))
   return result_string

def getActualValues(s_hci, s_mac) :
   # read the value characteristic (read handle is 0x003f)
   # handle returns 10 byte hex block containing temperature, humidity and batery level
   # the temperature consists of 3 bytes
   # Posivive value: byte 1 & 2 present the tenfold of the temperature
   # Negative value: byte 2 - byte 3 present the tenfold of the temperature
   raw_input = check_output(['gatttool', '-i', s_hci, '-b', s_mac, '--char-read', '--handle=0x003f']);
   if ':' in raw_input:
      raw_list    = raw_input.split(':')
      raw_data    = raw_list[1]
      raw_data    = raw_data.strip()
      octet_list  = raw_data.split(' ')
      t0 = int(octet_list[0], 16)
      t1 = int(octet_list[1], 16)
      t2 = int(octet_list[2], 16)
      if t2 == 255:
         temperature = (t1-t2)/10.0
      else:
         temperature = ((t0*255)+t1)/10.0
      humidity    = int(octet_list[4], 16)
      battery     = int(octet_list[9], 16)
   return (temperature, humidity, battery)

def getDeviceInfo(s_hci, s_mac) :
   # BeeWi Smart Climate handles
   # 0x0003 :    SmartClim name : 'Smart Clim'
   # 0x001b :      model number : 'BeeWi BBW200\00'
   # 0x001d :     serial number : '\00'
   # 0x001f : firmware revision : 'V1.5 R140514\00'
   # 0x0021 : hardware revision : '1.0\00'
   # 0x0023 : software revision : '\00'
   # 0x0025 :      manufacturer : 'Voxland\00'

   Name             = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x0003')
   ModelNumber      = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x001b')
   SerialNumber     = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x001d')
   FirmwareRevision = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x001f')
   HardwareRevision = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x0021')
   SoftwareRevision = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x0023')
   Manufacturer     = getResultStringForDeviceMacHandle(s_hci, s_mac, '0x0025')
   return (Name, ModelNumber, SerialNumber, FirmwareRevision, HardwareRevision, SoftwareRevision, Manufacturer)

def printHelp() :
   print 'Correct usage is "[sudo] beewiclim.py <device address> <command> [argument]"'
   print '       <device address> in the format XX:XX:XX:XX:XX:XX'
   print '       Commands:  stat          - Get status'
   print '       Commands:  val           - Get values (temperature, humidity, battery)'
   print '       Commands:  raw           - Get values (temperature, humidity, battery)'
   print '       [hci device] i.e. hci1 in case of multiple devices'
   print ''

if __name__=='__main__' :
   if os.geteuid() != 0 :
      print 'WARNING: This script may not work correctly without sudo / root. Sorry.'
   if len(sys.argv) < 3 :
      printHelp()
   else :
      hci_device = 'hci0' # default
      device_address = sys.argv[1]
      command = sys.argv[2]
      command = command.lower()
      error = ''
      if len(sys.argv) == 4 : hci_device = sys.argv[3]
      hci_device = hci_device.lower()

      # address shortcuts
      if device_address == 'sc1' : device_address = '5C:31:3E:XX:XX:XX'
      if device_address == 'sc2' : device_address = 'D0:5F:B8:XX:XX:XX'

      if len(device_address) != 17 :
         print 'ERROR: device address must be in the format NN:NN:NN:NN:NN:NN'
         exit()
      if 'stat' in command :
         name, model, serial, frevision, hrevision, srevision, manufacturer = getDeviceInfo(hci_device, device_address)
         temperature, humidity, battery = getActualValues(hci_device, device_address)
         print '-------------------------------------'
         print 'Device name       = ' + name
         print 'Model number      = ' + model
         print 'Serial number     = ' + serial
         print 'Firmware revision = ' + frevision
         print 'Hardware revision = ' + hrevision
         print 'Software revision = ' + srevision
         print 'Manufaturer       = ' + manufacturer
         print '-------------------------------------'
         print 'Temperature       = ' + str(temperature) + u'\u2103'.encode("utf8") # encode("utf8") needed on raspberry
         print 'Humidity          = ' + str(humidity) + '%'
         print 'Battery           = ' + str(battery) + '%'
         print '-------------------------------------'
      if 'val' in command :
         temperature, humidity, battery = getActualValues(hci_device, device_address)
         print '-------------------------------------'
         print 'Temperature       = ' + str(temperature) + u'\u2103'
         print 'Humidity          = ' + str(humidity) + '%'
         print 'Battery           = ' + str(battery) + '%'
         print '-------------------------------------'
      if 'raw' in command :
         temperature, humidity, battery = getActualValues(hci_device, device_address)
         print str(temperature),str(humidity),str(battery)
      if error != '' :
         if error == 'off' : error = 'ERROR: SmartClim ' + device_address
         print error
   exit()


2016-03-16
Update for negative temperatures and positive values over 25.5 degrees Celcius
Busy on pulling the historical data (temperature & humidity), having some troebles translating the data into values.

And sorry for the language mistakes, English is not my native language
Cheers!
Posts: 4
Joined: Sat Mar 12, 2016 3:57 pm
by Dragafe » Sun Mar 20, 2016 7:55 pm
Hi Vekfra, I see your post abd I want to ask you a question about Beewi's script. I have a bulb like Stephanie Marks and I want to use her script but it doesn't work. I can use "status" but it's the only code which I can use... You study her script and I want to know why It can't work ... Thanks.

PS : English isn't my native language.
Posts: 2
Joined: Sun Mar 20, 2016 7:33 pm
by deese » Sun May 08, 2016 11:31 pm
Hi,

The script is quite good, but the temperature readings are not represented correctly.

I haven't checked with negative temperatures but with this patch I'm seeing the correct temperature.
Thanks for sharing the code!

Code: Select all
--- beewiclim-orig.py   2016-05-08 23:26:48.120024401 +0000
+++ beewiclim.py    2016-05-08 23:28:20.679648390 +0000
@@ -70,9 +70,10 @@
       t1 = int(octet_list[1], 16)
       t2 = int(octet_list[2], 16)
       if t2 == 255:
-         temperature = (t1-t2)/10.0
+         temperature = (t1+(t2<<8))/10.0
       else:
-         temperature = ((t0*255)+t1)/10.0
+         #temperature = ((t0*255)+t1)/10.0
+    temperature = (t1 + (t2<<8))/10.0
       humidity    = int(octet_list[4], 16)
       battery     = int(octet_list[9], 16)
    return (temperature, humidity, battery)
@@ -145,7 +146,7 @@
       if 'val' in command :
          temperature, humidity, battery = getActualValues(hci_device, device_address)
          print '-------------------------------------'
-         print 'Temperature       = ' + str(temperature) + u'\u2103'
+         print 'Temperature       = ' + str(temperature) #+ u'\u2103'.encode("utf8")
          print 'Humidity          = ' + str(humidity) + '%'
          print 'Battery           = ' + str(battery) + '%'
          print '-------------------------------------'
Posts: 1
Joined: Sun May 08, 2016 11:25 pm
by faabbiii » Tue Jun 21, 2016 6:53 pm
Hi,

i need some help :?

I got the BeeWi BBW200-A10 and can connect it to my smartphone.

If i run hcitool scan i cant finde the BeeWi, but other Devices like my Smartphone.

I also try l2ping with the MAC of the BeeWi i got from the BeeWi App, but it only returns:

Can't connect: Host is down

I hope someone can help me :)

thx & greetz
Fabi

PS : Sorry, english isnt my native language.
Posts: 1
Joined: Tue Jun 21, 2016 6:41 pm
by vekfra » Thu Jun 23, 2016 6:38 pm
faabbiii wrote:Hi,

i need some help :?

I got the BeeWi BBW200-A10 and can connect it to my smartphone.

If i run hcitool scan i cant finde the BeeWi, but other Devices like my Smartphone.

I also try l2ping with the MAC of the BeeWi i got from the BeeWi App, but it only returns:

Can't connect: Host is down

I hope someone can help me :)

thx & greetz
Fabi

PS : Sorry, english isnt my native language.


Hi faabbii,

You cant find the BeeWi BBW200 using the "hcitool scan" command, the scan command is for Bluetooth only i.e. phone, tv, etc.
To scan for a Bluetooth 4.0 device (Bluetooth Low Energy or BLE) you have to use the command "hcitool lescan" and that is a neverending scan, you have to stop it using Ctrl+C.

Example output lescan:
Code: Select all
sudo hcitool lescan
LE Scan ...
5C:31:3E:4D:C6:3F (unknown)
5C:31:3E:4D:C6:3F BeeWi SmartClim 1
D0:5F:B8:51:A0:5E (unknown)
D0:5F:B8:51:A0:5E BeeWi SmartClim 2
5C:31:3E:4D:C6:3F (unknown)
5C:31:3E:4D:C6:3F BeeWi SmartClim 1
D0:5F:B8:51:A0:5E (unknown)
D0:5F:B8:51:A0:5E BeeWi SmartClim 2
5C:31:3E:4D:C6:3F (unknown)
D0:5F:B8:51:A0:5E (unknown)
D0:5F:B8:51:A0:5E BeeWi SmartClim 2
5C:31:3E:4D:C6:3F (unknown)
5C:31:3E:4D:C6:3F BeeWi SmartClim 1
D0:5F:B8:51:A0:5E (unknown)
D0:5F:B8:51:A0:5E BeeWi SmartClim 2
5C:31:3E:4D:C6:3F (unknown)
5C:31:3E:4D:C6:3F BeeWi SmartClim 1
^C

A BeeWi SmartClim will send 2 resonses when a lescan is active, one response containing the data and a response containing the device name.

For the security minding people: Yes you can see the device id's of my devices, but there is no security in the device, I did not find it, anyone that does a lescan within 30 meters or less from the devices can see this data anyway.

Good luck with your testing.
Posts: 4
Joined: Sat Mar 12, 2016 3:57 pm
by vekfra » Thu Jun 23, 2016 6:54 pm
The first example scanning the information from the BBW200 was setup by connecting to the device and reading the data, I found that this technique uses a lot of battery power, battery dead in 3 weeks, not 3 months.

Something new:
For my home setup of OpenHab I use the lescan without hcitool by BLE scanning in node.js using the noble addon. No connection to the devices needed.

The node.js code runs once and returns a json dataset. The script is called every minute in a openhab rule and the json data is used to update the openhab items.

The node.js code: scanBeeWi.js
Code: Select all
var noble = require('noble');

var SC1 = false;
var SC1T = '';
var SC1H = '';
var SC1B = '';
var SC2 = false;
var SC2T = '';
var SC2H = '';
var SC2B = '';
var TP1 = false;
var TP1S = "OFF"
var Count = 0;

function hexToInt(hex) {
    if (hex.length % 2 != 0) {
        hex = "0" + hex;
    }
    var num = parseInt(hex, 16);
    var maxVal = Math.pow(2, hex.length / 2 * 8);
    if (num > maxVal / 2 - 1) {
        num = num - maxVal
    }
    return num;
}


noble.on('stateChange', function(state) {
  if (state === 'poweredOn') {
    noble.stopScanning();
    noble.startScanning();
  } else {
    noble.stopScanning();
  }
});


noble.on('scanStop', function() {
    console.log('{"SC1Temp":"'+SC1T+'","SC1Humi":"'+SC1H+'","SC1Batt": "'+SC1B+'","SC2Temp":"'+SC2T+'","SC2Humi":"'+SC2H+'","SC2Batt": "'+SC2B+'","TPFrans":"'+TP1S+'"}');
    process.exit(0);
});


// Scan for the 3 devices (maximum 20 replies)
noble.on('discover', function(peripheral) {

    if ((peripheral.id == '5c313e4dc63f' || peripheral.id == 'd05fb851a05e')) {
        var data = peripheral.advertisement.manufacturerData.toString('hex');
        var Temp = parseFloat(hexToInt(data.substr(10, 2)+data.substr(8, 2))/10).toFixed(1);
        var Hum = Math.min(100,parseInt(data.substr(14, 2),16));
        var Bat = parseInt(data.substr(24, 2),16);

        if (!SC1 && peripheral.id == '5c313e4dc63f') {
            SC1 = true;
            SC1T = Temp;
            SC1H = Hum;
            SC1B = Bat;
        }

        if (!SC2 && peripheral.id == 'd05fb851a05e') {
            SC2 = true;
            SC2T = Temp;
            SC2H = Hum;
            SC2B = Bat;
        }
    }

    // TrackerPad
    if (peripheral.id == '5c313e4dc63f') {
        TP1 = true;
        TP1S = 'ON';
    }
    if ((Count > 20 || TP1) && (SC1 && SC2)) {
        noble.stopScanning();
    }

    Count = Count + 1;
});


OpenHab rule using scanBeeWi.js
Code: Select all
rule "Get BeeWi SmartClim data"
when
   System started or
   Time cron "0 * * * * ?"
then
   var String data

// Get BeeWi data (each item in json string)
   data = executeCommandLine("sudo /usr/local/bin/node /home/pi/scanBeeWi.js", 20000)
//   postUpdate(SC1data, data)
   postUpdate(SC1Temp,transform("JSONPATH","$.SC1Temp",data))
   postUpdate(SC1Humi,transform("JSONPATH","$.SC1Humi",data)
   postUpdate(SC1Batt,transform("JSONPATH","$.SC1Batt",data)
   postUpdate(SC2Temp,transform("JSONPATH","$.SC2Temp",data))
   postUpdate(SC2Humi,transform("JSONPATH","$.SC2Humi",data)
   postUpdate(SC2Batt,transform("JSONPATH","$.SC2Batt",data)
   postUpdate(TPFrans,transform("JSONPATH","$.TPFrans",data)
end

Yes you can see the device id's of my devices, but there is no security in the device, I did not find it, anyone that does a lescan within 30 meters or less from the devices can see this data anyway.

Happy testing :-)
Posts: 4
Joined: Sat Mar 12, 2016 3:57 pm
by enrimilan » Mon Apr 24, 2017 2:55 pm
Hey there!

First, I would like to thank you for sharing your code here, awesome!

I created a new repository for collecting different code examples in order to interact with the device:
https://github.com/enrimilan/BeeWi-BBW200-Reader

I hope this could be helpful too ^^

Regards
Posts: 1
Joined: Mon Apr 24, 2017 2:47 pm
Location: Vienna, Austria