First of all I would like to Thank you Silicon Labs for the Thunderboard Sense Kit ! Tiny but Swiss Knife of Sensors.
Trust me it is !
I have decided to go with IoT demo using this kit which sends Temperature, Humidity and Battery Level to Cloud.
I choose RaspberryPi 3 Model B to collect the data from Sense Kit and then upload it to https://thingspeak.com/ portal.
Thingspeak is very easy to create and use platform. I have created my channel there with three fields. It gives you unique API Key using which you can push data to cloud and on Thingspeak you can view the graph of your logged data. There is limit on it so you can push data once at every 15 seconds only.
Thingspeak Dashboard !
Thingspeak Graph !
Project posted by @Namo_Aton helped me to to start things and find characteristics I want to read out and push data to cloud.
As I want to read Battery Level, Temperature and Humidity I have find out those three characteristics first and then read it. It will read parameters at every 1 second but push to cloud at 15 second interval.
Here is the python script to connect with Sense Kit, Read data and push to Cloud.
from __future__ import division
import sys
from bluepy.btle import *
import struct
import thread
from time import sleep
import urllib2
#
PRIVATE_KEY = '2HL151HLWNJNENQD'
#Base URL of Thingspeak
baseURL = 'https://api.thingspeak.com/update?api_key='
def vReadSENSE():
scanner = Scanner(0)
devices = scanner.scan(3)
for dev in devices:
print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
for (adtype, desc, value) in dev.getScanData():
print " %s = %s" % (desc, value)
num_ble = len(devices)
print num_ble
if num_ble==0:
return None
ble_service = []
char_sensor = 0
non_sensor = 0
bat_char = Characteristic
temperature_char = Characteristic
humidity_char = Characteristic
count = 15
for i in range(num_ble):
try:
devices[i].getScanData()
ble_service.append(Peripheral())
ble_service[char_sensor].connect(devices[i].addr,devices[i].addrType)
char_sensor = char_sensor + 1
print "Connected %s device with addr %s " % (char_sensor, devices[i].addr)
except:
non_sensor = non_sensor + 1
try:
for i in range(char_sensor):
services = ble_service[i].getServices()
characteristics = ble_service[i].getCharacteristics()
for k in characteristics:
print k
if k.uuid=="2a19":
print "Battery Level"
bat_char = k
if k.uuid == "2a6e":
print "Temperature"
temperature_char = k
if k.uuid == "2a6f":
print "Humidity"
humidity_char = k
except:
return None
while True:
bat_data = bat_char.read()
bat_data_value = ord(bat_data[0])
temperature_data = temperature_char.read()
temperature_data_value =(ord(temperature_data[1])<<8)+ord(temperature_data[0])
float_temperature_data_value = (temperature_data_value / 100)
humidity_data = humidity_char.read()
humidity_data_value =(ord(humidity_data[1])<<8)+ord(humidity_data[0])
print "Battery: ", bat_data_value
print "Temperature: ", float_temperature_data_value
print "Humidity: ", humidity_data_value
if count > 14:
f = urllib2.urlopen(baseURL + PRIVATE_KEY +"&field1=%s&field2=%s&field3=%s" % (bat_data_value, float_temperature_data_value, humidity_data_value))
print f.read()
f.close()
count = 0
count = count + 1
sleep(1)
while True:
vReadSENSE()
What's more Christmas-y than the entire office decorated in multi-colored LEDs? After my last attempt at creating a wireless network I realized that a simple point-to-point network does not scale to the level of our entire office. So for the next iteration i chose to jump on the protocol of choice for indoor connected nodes: Thread.
I started out with zero knowledge about this and ended up with 18 Thread-connected nodes all polling the main server for a color. The nodes are implemented on Thunderboard Sense and glows in different colors dictated by the server. The server can either provide a fixed color or do a mode where it cycles through the colors along the edges of the RGB-gamut. Here's a couple of pictures from the installation. Detailed instructions below the pics.
The commissioning Thread server and one node.
Multiple Thread nodes all glowing in the same color.
Thread nodes all glowing around the office.
Thread nodes in every corner of the office.
Detailed description
Step 1: Get started
The first thing I did was get the client/server example up running on two WSTKs. This example is using CoAP for communication between a client and a server, very much like communication between a webclient and a webserver using HTTP. You can use POST commands to push data to the server and GET commands to retrieve data back. For the initial phase I just followed QSG113: Getting Started with Silicon Labs Thread.
It's best to remove bootloader, you can do that in the .isc file by configuring "HAL->Bootloader->None" and unchecking the box "Plugins->Common->TFTP Bootload Target", and then commenting out the non-compiling bits in client-implementation.c and server-implementation.c. If you remove the bootloader you can just press the debug-button in Simplicity Studio to run code on the device.
Step 2: Get it running on a Thunderboard Sense
The next thing I had to do was to get our Thread stack running on a Thunderboard Sense. The first thing I did was to create a new client-project under a different name, I used client_tbs. I then removed the bootloader as outlined above and changed the target part to EFR32MG1P132F256M48 and hit 'Generate'. After removing the boorloader parts from client-implementation.c this should run on the Thunderboard Sense, reporting back the temperature.
To get it properly working with the peripherals on the actual board I did two things: 1) Update the buttons/LEDs and 2) include the BSP from the Bluetooth example.
Getting it to work with the correct buttons and LEDs I copied the folder EFR32MG1_BRD4151A into my project and renamed it to EFR32MG1_BRD4160A. I then updated the bspconfig.c with the correct locations of the LEDs and buttons:
If you then change the include path to this folder instead of the EFR32MG1_BRD4151A, the project should compile and you will get a green blinking LED.
To get the BSP running you first have to copy the neccessary contents from SimplicityStudio\v4\offline\examples\ble_2000\examples_thunderboard_sense\bsp into your project. For this project I'm just using the PWM LEDs and the Temp/Humidity sensor, so I copied:
As the BOARD.c BSP relies on the systick-timer you have to add the following to the top of client-implementation.c to route the systick interrupt to the correct location:
The function emberAfMainCallback is run immediately on boot. A stub for this function is located in thread-callback-stubs.c by default, so remove it from here. The second thing you have to do is in main.c move the INTERRUPTS_ON(); above emAfMain(MAIN_FUNCTION_ARGUMENTS); as interrupts are needed for initializing the BSP:
int MAIN(MAIN_FUNCTION_PARAMETERS)
{
// Enable interrupts before main-init
INTERRUPTS_ON();
// Let the application and plugins do early initialization. This function is
// generated.
emAfMain(MAIN_FUNCTION_ARGUMENTS);
(...)
You should now be able to use all the BSP-functions of the Thunderboard Sense. For example, getting the actual temperature of the RH/temp sensor to report back to the server by replacing data = getTemp_mC(); with:
To the emberAfCoapDispatchTable[] in thread-coap-dispatch.c. This means that the server will run clientGetHandler every time it gets a GET request from a client. In server-implementation.c a corresponding handler will have to be added for this:
void clientGetHandler(const EmberCoapMessage *request)
{
// Requests from clients are sent as CoAP GET requests to the "client/get"
// URI.
EmberCoapCode responseCode;
if (state != ADVERTISE) {
responseCode = EMBER_COAP_CODE_503_SERVICE_UNAVAILABLE;
} else {
if (!colorFixed)
incrementColorIndex();
coapmessage[0] = colorTableSine[colorIndex][0];
coapmessage[1] = colorTableSine[colorIndex][1];
coapmessage[2] = colorTableSine[colorIndex][2];
emberAfCorePrint("Sending %ld %ld %ld to client at ", coapmessage[0], coapmessage[1], coapmessage[2]);
emberAfCoreDebugExec(emberAfPrintIpv6Address(&request->remoteAddress));
emberAfCorePrintln("");
responseCode = EMBER_COAP_CODE_205_CONTENT;
}
if (emberCoapIsSuccessResponse(responseCode)
|| request->localAddress.bytes[0] != 0xFF) { // not multicast
emberCoapRespond(responseCode, coapmessage, 3); // Payload
}
}
The rest of the additions to server-implementation.c looks like this:
As you can see the two buttons can change between a mode where the color is fixed across the network and a mode where we cycle through the RGB-gamut. I had to create a non-linear color table (colorTableSine) because our eyes will view all shades in the corners of the gamut as that color, and if you cycle the colors linearly it will look like it's racing past the intermediate colors (purple, teal and yellow).
Client:
In client-implementation.c you can then replace the contents of reportDataToServer with a function that will run a GET-command instead of the POST-command. My version of reportDataToServer looks like this:
static void reportDataToServer(void)
{
// We peridocally get data from the server.
// The actual data is read and used in processServerDataGet()
EmberStatus status;
status = emberCoapGet(&server,
clientGetUri,
processServerDataGet);
if (status == EMBER_SUCCESS) {
setNextState(WAIT_FOR_DATA_CONFIRMATION);
} else {
emberAfCorePrintln("ERR: Reporting failed: 0x%x", status);
repeatStateWithDelay(REPORT_PERIOD_MS);
}
}
As you might guess you also have to add a processServerDataGet. This looks like this:
static void processServerDataGet(EmberCoapStatus status,
EmberCoapMessage *coap,
void *appData,
uint16_t appDatalength)
{
// We track the success or failure of reports so that we can determine when
// we have lost the server. A series of consecutive failures is the trigger
// to detach from the current server and find a new one. Any successfully-
// transmitted report clears past failures.
if (state == WAIT_FOR_DATA_CONFIRMATION) {
if (status == EMBER_COAP_MESSAGE_ACKED
|| status == EMBER_COAP_MESSAGE_RESPONSE) {
failedReports = 0;
} else {
failedReports++;
emberAfCorePrintln("ERR: Report timed out - failure %u of %u",
failedReports,
REPORT_FAILURE_LIMIT);
}
if (failedReports < REPORT_FAILURE_LIMIT) {
setNextStateWithDelay(REPORT_DATA_TO_SERVER, REPORT_PERIOD_MS);
} else {
detachFromServer();
}
}
uint8_t coapmessage[4] = {0};
// Getting the contents of the CoAP GET request
MEMCOPY(coapmessage, (void*)coap->payload, coap->payloadLength);
// Set the color of the LEDs accordingly
BOARD_rgbledSetColor(coapmessage[0], coapmessage[1], coapmessage[2]);
// Printing the response for debugging purposes
emberAfCorePrint("Got %ld %ld %ld from ", coapmessage[0], coapmessage[1], coapmessage[2]);
emberAfCoreDebugExec(emberAfPrintIpv6Address(&server));
emberAfCorePrintln("");
}
That's it! Here's another picture of multiple Thread nodes all lighting in the same color:
Projects
IoT demo using Thunderboard
Hello,
First of all I would like to Thank you Silicon Labs for the Thunderboard Sense Kit ! Tiny but Swiss Knife of Sensors.
Trust me it is !
I have decided to go with IoT demo using this kit which sends Temperature, Humidity and Battery Level to Cloud.
I choose RaspberryPi 3 Model B to collect the data from Sense Kit and then upload it to https://thingspeak.com/ portal.
Thingspeak is very easy to create and use platform. I have created my channel there with three fields. It gives you unique API Key using which you can push data to cloud and on Thingspeak you can view the graph of your logged data. There is limit on it so you can push data once at every 15 seconds only.
Thingspeak Dashboard !
Thingspeak Graph !
Project posted by @Namo_Aton helped me to to start things and find characteristics I want to read out and push data to cloud.
As I want to read Battery Level, Temperature and Humidity I have find out those three characteristics first and then read it. It will read parameters at every 1 second but push to cloud at 15 second interval.
Here is the python script to connect with Sense Kit, Read data and push to Cloud.
Here is the video for the same.
Cheers !
Threading the office: Thunderboard Sense on Thread
Summary
What's more Christmas-y than the entire office decorated in multi-colored LEDs? After my last attempt at creating a wireless network I realized that a simple point-to-point network does not scale to the level of our entire office. So for the next iteration i chose to jump on the protocol of choice for indoor connected nodes: Thread.
I started out with zero knowledge about this and ended up with 18 Thread-connected nodes all polling the main server for a color. The nodes are implemented on Thunderboard Sense and glows in different colors dictated by the server. The server can either provide a fixed color or do a mode where it cycles through the colors along the edges of the RGB-gamut. Here's a couple of pictures from the installation. Detailed instructions below the pics.
The commissioning Thread server and one node.
Multiple Thread nodes all glowing in the same color.
Thread nodes all glowing around the office.
Thread nodes in every corner of the office.
Detailed description
Step 1: Get started
The first thing I did was get the client/server example up running on two WSTKs. This example is using CoAP for communication between a client and a server, very much like communication between a webclient and a webserver using HTTP. You can use POST commands to push data to the server and GET commands to retrieve data back. For the initial phase I just followed QSG113: Getting Started with Silicon Labs Thread.
It's best to remove bootloader, you can do that in the .isc file by configuring "HAL->Bootloader->None" and unchecking the box "Plugins->Common->TFTP Bootload Target", and then commenting out the non-compiling bits in client-implementation.c and server-implementation.c. If you remove the bootloader you can just press the debug-button in Simplicity Studio to run code on the device.
Step 2: Get it running on a Thunderboard Sense
The next thing I had to do was to get our Thread stack running on a Thunderboard Sense. The first thing I did was to create a new client-project under a different name, I used client_tbs. I then removed the bootloader as outlined above and changed the target part to EFR32MG1P132F256M48 and hit 'Generate'. After removing the boorloader parts from client-implementation.c this should run on the Thunderboard Sense, reporting back the temperature.
To get it properly working with the peripherals on the actual board I did two things: 1) Update the buttons/LEDs and 2) include the BSP from the Bluetooth example.
Getting it to work with the correct buttons and LEDs I copied the folder EFR32MG1_BRD4151A into my project and renamed it to EFR32MG1_BRD4160A. I then updated the bspconfig.c with the correct locations of the LEDs and buttons:
If you then change the include path to this folder instead of the EFR32MG1_BRD4151A, the project should compile and you will get a green blinking LED.
To get the BSP running you first have to copy the neccessary contents from SimplicityStudio\v4\offline\examples\ble_2000\examples_thunderboard_sense\bsp into your project. For this project I'm just using the PWM LEDs and the Temp/Humidity sensor, so I copied:
As the BOARD.c BSP relies on the systick-timer you have to add the following to the top of client-implementation.c to route the systick interrupt to the correct location:
To initialize the BSP you add the following in the top of the same file:
The function emberAfMainCallback is run immediately on boot. A stub for this function is located in thread-callback-stubs.c by default, so remove it from here. The second thing you have to do is in main.c move the INTERRUPTS_ON(); above emAfMain(MAIN_FUNCTION_ARGUMENTS); as interrupts are needed for initializing the BSP:
You should now be able to use all the BSP-functions of the Thunderboard Sense. For example, getting the actual temperature of the RH/temp sensor to report back to the server by replacing data = getTemp_mC(); with:
Step 3: Use CoAP GET to get the colors from the server
The original example was only using POST, so the third task was to get the application to use GET instead.
Server:
On the server side you should add:
To the emberAfCoapDispatchTable[] in thread-coap-dispatch.c. This means that the server will run clientGetHandler every time it gets a GET request from a client. In server-implementation.c a corresponding handler will have to be added for this:
The rest of the additions to server-implementation.c looks like this:
As you can see the two buttons can change between a mode where the color is fixed across the network and a mode where we cycle through the RGB-gamut. I had to create a non-linear color table (colorTableSine) because our eyes will view all shades in the corners of the gamut as that color, and if you cycle the colors linearly it will look like it's racing past the intermediate colors (purple, teal and yellow).
Client:
In client-implementation.c you can then replace the contents of reportDataToServer with a function that will run a GET-command instead of the POST-command. My version of reportDataToServer looks like this:
As you might guess you also have to add a processServerDataGet. This looks like this:
That's it! Here's another picture of multiple Thread nodes all lighting in the same color:
Merry Christmas!