Since 1988, our town of Holland, Michigan, best known for its annual tulip festival, diverted waste heat from its power plant into pipes that run under streets and sidewalks in the central business district. For years we have enjoyed open, snow-free, access to our downtown, especially in hard, freezing winters with their lake-effect snow storms.
Learn more about our Snowmelt System
We are currently building a new power plant, and have not only connected our snowmelt system to it, but have expanded the system even further, now covering near five miles of sidewalks and roadway.
But how well is it working? We can see our sidewalks, but do not have quantitative surface data to show how well the snowmelt performs throughout the city. Are we supplying enough heat to melt the snow? Are we wasting energy by putting too much heat into the system? How should we run the system pumps? We need a device that can monitor performance in various locations over time, and help us make informed decisions as to how to run our snowmelt system.
We need a Snowmelt monitor. This device can be placed on the sidewalk anywhere in the system to measure:
- Ground Temperature
- Surface wetness
The device looks much as a traffic counter does - a small box chained to a nearby structure such as a lamp post or a tree. Data collected from the monitor is sent via AT&T to PubNub, where the data can be displayed, analyzed and sent into Snowmelt monitoring systems. With this data informed decisions can be made.
As you can see, there are lots of pieces to this project. From hardware to cloud service integration. Any single component is enough for many projects. This project focuses on integration of all of them, and assumes you know your way around code and online services. It's a bit of an adventure. Are you ready?
Getting Started with the AT&T IOT IoT KitThe best way to get started with your board is to follow Avnet Maker Faire Labs at: http://cloudconnectkits.org/system/files/MasterMakerFaire.pdf
This is a straight forward way to get your K64F and cellular shield up and running, and only takes an hour. By following these instructions, you will have a base foundation upon which to build. You will learn:
- How to program the K64F with the online mbed IDE
- Set up the Avnet cellular shield
- Program an example program
- Set up AT&T SIM, and run the program.
You now have your local environment ready with power and programming.
A couple notes on this step:
- Windows users, you may need to install
mbed
serial driver from https://developer.mbed.org/handbook/Windows-serial-configuration - I seemed to have had installed the firmware, as I got stuck in bootloader mode. You will know if you have this issue if you see "bootloader" attach to yor PC instead of "
mbed
" as a disk attachment. Here's the firmware: https://developer.mbed.org/handbook/Firmware-FRDM-K64F - Now might be a good time to update the firmware on your cellular shield as well. Visit https://starterkit.att.com/tutorials/cellular-shield-firmware-upgrade and follow the steps very closely. Enjoy having to run the installer 3 times. Because third time's a charm!
Now that you have your board up and talking to the net, let's get it online with the systems we need. AT&T offers two great tools - M2X and Flow.
AT&T M2X provides time-series data storage, device management, message brokering, event triggering, alarming, geo-fencing, and data visualization for your industrial Internet of Things (IOT) products and services.
Flow Designer is a robust web-based development environment where data driven applications can be designed and deployed with ease.
The best way to get going with these services is to follow Avnet guide at: http://cloudconnectkits.org/system/files/GettingStartedGuide_ATT_IOT_rv1-3.pdf
Since you've already gone through the easier Maker Faire labs, this is a bit redundant. But, trust me, it's worth going through it a second time. You will start to feel at home with mbed
.
Once you are done with this, you will have:
- The Starter Kit Flow, that you can edit to do your bidding
- M2X collecting Data
- A nice
Avnet_ATT_Cellular_IOT
project in yourmbed
IDE that you can change for the better.
PubNub is a very interesting message handling system that allows you to move your data from one application to another. From one to many users. This project uses PubNub as a tool for graphing data.
Let's get to it:
- Create an account at pubnub.com
- Create a New App by entering a name and pressing the big green button
- Note here that you have a Demo Keyset. We can use that for starters.
- Now, move over to Flow, and access your Starter Kit code.
We are going to take the data flow that we already are sending to M2X, and send it to Pubnub. To do this, we are going to use the import function in Flow.
- Click on the "
hamburger
" icon in the upper right corner. It looks like 3 lines. Then choose import, Clipboard. This will allow you to import the following text:
[{"id":"33ddf60a.d8026a","type":"pubnub-keys","z":"828b2334.7d74e","pub_key":"pub-KEY","sub_key":"sub-KEY"},{"id":"611c3260.7f625c","type":"pubnub out","z":"828b2334.7d74e","keys":"33ddf60a.d8026a","channel":"SnowMelt","x":819.328125,"y":549,"wires":[]}]
This will create a new flow node. Place it next to the Heat Index node, and then connect it up, like this:
Go ahead and click on this new node and set the keys. Those are over on your Pubnub page.
Click over to Pubnub, and select your project. Select your keys, and then click on the Debug Console on the left side. You should see a console window showing that it is now receiving data from Flow:
Note something interesting here (besides my extra data fields): My data is wrapped in an "eon
" identifier. This is an added data node that allows us to use EON graphing. More on that later. But for now, since we are working in Flow, let's go ahead and modify the data stream to add this "eon
", so we will be set for graphs later.
- Back to flow.
- On the left side search, type "
function
", and drag one onto the work surface, next to the PubNub node. - Click on it, and add this code:
// if you want to use EON graphing,
// you need to wrap the payload with "eon"
//
msg.payload = {
"eon": {
"temp": msg.payload.temp,
"humidity": msg.payload.humidity,
"heatIndex": msg.payload.heatIndex
}
};
return msg;
Nice. Talk about an easy function. We are just adjusting the msg.payload that came into the bubble to go out as something else.
- Click on the wire connecting the heat index to the Pubnub out bubble, and rewire things like this:
Now the data flowing out of the Heat Index is rewritten before posting to PubNub. Nice! Functions are very powerful. Go ahead and take a look at the HeatIndex node. See the code there? Good stuff.
Adding SensorsLet's add the analog light sensor to our system. Go ahead and wire up your light sensor as follows:
- Sensor GND to GND
- Sensor VCC to 3V3
- Sensor OUT to A0
I have no idea why pin identification is hard. But it is, at least for me. We are looking at the left side of the diagram. The 3v3 and GND are in red, and A0 is in green.
The cellular shield headers carry the OUTER pins through. I think you need to stay away from A4, A5, D14 and D15, as they are connected to devices on the cellular shield.
If you look into the code you will see DigitalOut definitions that identify D1, D2, D6, D8, D9 and D10 in use by the modem. Stay away from those pins as well!
Great. Let's update our K64F Code to read the sensor. In mbed
, go to your sensors.cpp file. search for the line "} //Read_HTS221()
" about 422 lines down. Add the following code.
// Light Sensor
AnalogIn light(A0);
void Read_Light()
{
sprintf(SENSOR_DATA.Light, "%0.2f", light.read());
printf("light in = %s\n\r", SENSOR_DATA.Light);
}
While we're here, you need to add a call to this new subroutine in the subroutine that calls it - read_sensors()
, at the bottom of sensors.cpp.
I love programming. Add your new routine to the read_sensors
subroutine, like this:
void read_sensors(void)
{
Read_HTS221();
Read_Si7020();
Read_Si1145();
Read_motion_sensor();
Read_GPS();
Read_Snow();
Read_Light();
} //read_sensors
We are going to read the light level on A0 and post it to the SENSOR_DATA
string. The string needs to be modified to have light as well. Where's that? Glad you asked. Go to Sensors.h
and scroll down to the bottom. Add a line right after "GPS_Course
":
char Light[SENSOR_FIELD_LEN_LIMIT];
We also need to add light to our send string. In Config_me.h
, Search for your iSensorsToReport,
and add a new type. Mine's snowmelt
:
#define TEMP_HUMIDITY_ONLY 1
#define TEMP_HUMIDITY_ACCELEROMETER 2
#define TEMP_HUMIDITY_ACCELEROMETER_GPS 3
#define TEMP_HUMIDITY_ACCELEROMETER_PMODSENSORS 4
#define TEMP_HUMIDITY_ACCELEROMETER_PMODSENSORS_VIRTUALSENSORS 5
#define SNOWMELT 6
static int iSensorsToReport = SNOWMELT; //modify this to change your selection
Now head over to main.ccp
, and add a new case statement in the iSensorsToReport
that looks like this:
case SNOWMELT:
// Modified for pete's sensor array
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&light=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.Light, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
This is actually the URL that is sent to feed Flow. Pretty cool, huh? Note how we have added "&light=%s
" to the string, and then "SENSOR_DATA.Light
". Run your program, and watch your serial USB output. You should see:
light in = 0.52
Sending to modem : GET /DEMO/in/flow/climate?serial=snowmelt001&temp=91.86&humidity=24&light=0.52 HTTP/1.1
Host: run-east.att.io
JSON : {"status":"accepted"}
We're not done yet. We need to add Light into our Flow! Head back to flow, and add Light
to the list of data nodes:
"light": msg.payload.light,
Do the same for the M2X Lead-in function. I bet you can figure out the code. Check your PubNub quick. Look at that, you have Light
in your data stream now. Nice.
Let's head over to M2X quick, and check it out there. Click on your device, and add a stream. Caps are important here. Make sure light is light, and not Light. Awesome. You are collecting your light data at M2X:
We can add new data to our system. Let's make some charts! PubNub EON reads your channels and plots them in various ways. First go ahead and browse the PubNub EON site at: https://www.pubnub.com/developers/eon/
Or, maybe watch this video:
On a webserver, create a file snowmelt.html and paste code you see in the code section below. Adjust the keys and variables to suit your data stream. Done. If you are a web developer, you can do some magic and make your dashboard look pretty good.
EON is based on C3.js. You can refer to the C3.js documentation for more chart tweaking
Adding Wunderground Weather DataYou may have noticed that my charts have some real-time weather data as well. This is not from our sensor, but from Wunderground. We built a flow to bring Wunderground data into PubNub!
Let's do it.
- Go to Wunderground API and get yourself an API Key.
- Have your PubNub keys handy.
- Add this code on a new workspace in your Flow, and change the KEY values and your ZIP:
[{"id":"90bbb736.cc7808","type":"pubnub-keys","z":"d30b5571.17e828","pub_key":"pub-KEY","sub_key":"sub-KEY"},{"id":"eaabb110.011ae","type":"inject","z":"d30b5571.17e828","name":"Repeat Every 30 minutes","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"*/30 0 * * *","once":false,"x":159.875,"y":133,"wires":[["a5e296d2.070fa8"]]},{"id":"a5e296d2.070fa8","type":"http request","z":"d30b5571.17e828","name":"Get Openweather 49423 Current Wx","method":"GET","ret":"txt","url":"http://api.wunderground.com/api/YOURKEY/conditions/q/YOURZIP.json","configKey":"","username":"","password":"","useAuth":false,"encryption":"none","useCertificate":false,"decrypt":false,"cert":"","key":"","encryptObj":["username","password"],"x":324.875,"y":236,"wires":[["944c5c7b.3c29d"]]},{"id":"749fcf8b.c2ea1","type":"debug","z":"d30b5571.17e828","name":"","active":false,"console":"false","complete":"wx-payload","x":967.875,"y":309,"wires":[]},{"id":"944c5c7b.3c29d","type":"json","z":"d30b5571.17e828","name":"","x":519.875,"y":305,"wires":[["bbae9c49.6d852"]]},{"id":"bbae9c49.6d852","type":"function","z":"d30b5571.17e828","name":"Parse out temp","func":"var temp = msg.payload.current_observation.temp_f;\nvar humidity = msg.payload.current_observation.relative_humidity;\nvar wind = msg.payload.current_observation.wind_string;\nvar weather = msg.payload.current_observation.weather;\nvar wind_mph = msg.payload.current_observation.wind_mph;\nvar wind_gust_mph = msg.payload.current_observation.wind_gust_mph;\nvar precip_1hr_in = msg.payload.current_observation.precip_1hr_in;\n\nmsg.payload = {\n \"eon\": {\n \"temperature\": temp,\n \"humidity\": humidity,\n \"weather\": weather,\n \"wind\": wind,\n \"wind_mph\": wind_mph,\n \"wind_gust_mph\": wind_gust_mph,\n \"precip_1hr_in\": precip_1hr_in\n }\n };\n\nreturn msg;","outputs":1,"noerr":0,"dependencies":[],"x":716.875,"y":370,"wires":[["749fcf8b.c2ea1","862e9839.f65398"]]},{"id":"862e9839.f65398","type":"pubnub out","z":"d30b5571.17e828","keys":"90bbb736.cc7808","channel":"wx","x":962.875,"y":434,"wires":[]},{"id":"b3f155c6.683408","type":"comment","z":"d30b5571.17e828","name":"Wunderground To PubNub","info":"Read wunderground weather api, and send to wx channel at pubnub","x":163.59375,"y":71,"wires":[]}]
Now, go back to Pubnub, and start a debug session on a channel called "wx
". Next, go back to Flow and click the blue dot next to the INJECT node to start the flow. Back in PubNub. Tada! Data! And, look, it's ready to use in EON.
One more thing! If the probe temperature goes to 32, we want the system to send us a tweet. We will need to:
- Create a flow function that will test the temp and fire off a message to a PubNub channel called twitter-input.
- Set up PubNub to monitor twitter-input and act accordingly.
First, let's do the PubNub part. Go to https://apps.twitter.com/ and create a new app. This will give you your API keys.
Yes, I erased mine.
Now let's create the Pubnub Block. Visit https://www.pubnub.com/blocks-catalog/twitter/ and click Try it Out. Chose your app and keyset, and import the block. You will be presented with the code. Simply edit your keys into it.
Click Start in the upper right, and then publish on the test payload. You should see a tweet show up from your twitter account in your twitter stream. You can also open another window and check out the debug by subscribing to twitter: input. Send another test tweet (probably with different text) and see the results:
Okay, let's get Flow to send us tweets when it's cold. Access your flow, and import the following code:
[{"id":"33ddf60a.d8026a","type":"pubnub-keys","z":"828b2334.7d74e","pub_key":"pub-cKEY","sub_key":"sub-c-KEY"},{"id":"3850ec25.6d7374","type":"pubnub out","z":"828b2334.7d74e","keys":"33ddf60a.d8026a","channel":"twitter-input","x":1170.875,"y":665,"wires":[]},{"id":"81831022.4d9d2","type":"function","z":"828b2334.7d74e","name":"Check for Freezing Temperature","func":"// if temperature is <= 32 send a direct message tweet to a user\n\nuser = \"kayakpete\"; // change to your user name\n\nvar freezing = context.get('freezing')||0; // Get current freezing status\n\ntemp = msg.payload.probe0;\n\nif (temp <= 32) { // If it's freezing\n if (freezing===0) { // And wasn't freezing before\n msg.payload = {\"tweet\": \"DM \" + user + \" Freezing at \"+ msg.payload.probe0 + \"F\"};\n freezing = 1;\n }\n else freezing = 1; // It's freezing, or still freezing\n}\nif (temp >32) { \n freezing = 0;\n}\n\ncontext.set('freezing',freezing); // remember for next time\nmsg.freezing = freezing;\nreturn msg;","outputs":1,"noerr":0,"dependencies":[],"x":740.875,"y":592,"wires":[["88bbe03.6f76f2","3850ec25.6d7374","52e365e5.7871dc"]]},{"id":"88bbe03.6f76f2","type":"debug","z":"828b2334.7d74e","name":"Temperature","active":true,"console":"false","complete":"payload","x":1077.59375,"y":552,"wires":[]},{"id":"52e365e5.7871dc","type":"debug","z":"828b2334.7d74e","name":"Freezing","active":true,"console":"false","complete":"freezing","x":1077.609375,"y":600,"wires":[]}]
Set your keys, and connect that up to the back of your Heat-Index node.
The Check for Freezing Temperature node is interesting in that it remembers the current freezing state, so you don't get tweeted every time the flow is called. Node-Red (Flow) calls this a context variable. It remembers the value from flow call to flow call. Very handy!
We learned a lot in developing this project. Here's some great hints for you:
- The folks in
#att
and#development
at the HacksterLive slack channel are your friends. They are great at helping out. Check them out: http://slack.hackster.io/ - The
mbed
online development system is really nice. Be sure to look at example code. It is easy to import the code to your IDE, and start messing with it. I used this to find code to run my 1-wire temperature sensors, for example. - Depending on your project, you might want to consider adjusting your polling time. In the
Config_me.h
, change your interval as needed. Save data, save $.
// This constant defines how often sensors are read and sent up to FLOW
#define SENSOR_UPDATE_INTERVAL_MS 5000; //5 seconds
// #define SENSOR_UPDATE_INTERVAL_MS 60000; //1 minute
// #define SENSOR_UPDATE_INTERVAL_MS 1800000; //30 minute
// #define SENSOR_UPDATE_INTERVAL_MS 3600000; //1 hour
- When you reboot the K64F, you will see the board LED go white (booting), then red (Connecting to cell system), then green (transmitting). This is the normal operation.
Our local Board of Public Works, who manages the snowmelt system, is very interested in this project. I've started work work with BPW engineers to move from this proof-of-concept prototype to a version that would be ready for regular use. We are thinking of building the system right into one or two bricks!
The combination of the AT&T starter kit, AT&T cloud services and PubNub is an extremely powerful way to get your IOT project online. This project only scratches the surface of what is possible with these systems.
What will you build? Let me know!
All the Links- AT&T IOT Starter Kit: https://starterkit.att.com/
- Mbed: https://developer.mbed.org
- AT&T Flow: https://flow.att.io
- AT&T M2X: https://m2x.att.com
- PubNub: http://pubnub.com
- PubNub Eon: https://www.pubnub.com/developers/eon/
- Hackster: http://hackster.io
- Slack: http://slack.hackster.io/
This project has been selected as the winner of the Realtime AT&T IoT StarterKit challenge! Fantastic!
Update January 4, 2016I went to Las Vegas to attend the AT&T Developer Summit where I presented on the sensor, and the process of developing it quickly. The project was well received by an audience of over 200 people.
The project is proceeding nicely to a phase two prototyping process. We have brought mechanical engineers with the power plant in to the project to work out further detail as to what the sensor might look like fully installed. Here's a mock-up drawing of the sensor, with batteries and thermo-electric power production. Pretty awesome!
- Lakeshore Innovator of the Year, 2020
- Won the Realtime AT&T IoT Starter Kit Challenge
- Presented at Grand Rapids Startup Weekend 2017. RunEngine Article
- Noted in the mbed developer blog
- Highlighted in AT&T IoT Developer Stories
Comments