Securing and monitoring a family's recreational vehicle (RV) travel trailer or camper investment requires considering both home and vehicle aspects of a system. A modern RV trailer is a home on wheels. Typically, when not in use they are stored at a distant facility. I know, we own a rather expensive Airstream travel trailer. Even while using them for vacation travel, they will be parked unattended for long periods while the family is off enjoying the vacation sites. Often RV storage facilities and campgrounds are remote with little or no security. The internet is, of course, rife with horror stories of RVs damaged or destroyed by weather events. An RV owner is always concerned about the state of her RV. Is the near-freezing temperature endangering the plumbing? Is the RV battery dying leaving some critical systems inoperative? Has some thief broken in, or worse, hitched up and towed away the families investment?
The projectA mobile network connected system is perfectly suited for RV monitoring. It provides the internet connection needed while on the go. I have personally been waiting for just such a solution as AT&T's LTE connected IoT development system. This project is a monitoring and security system for our Airstream that lets us keep tabs on it while it sits in storage or at a campground. I've got a list of things that I want to monitor already. There are three things that mostly keep me worried when our Airstream is in storage, is the battery dead, is cold enough to winterize (or, conversely, warm enough to start the season!), and has someone driven off with it. Therefore, I put monitoring those three things at the top of the list:
- RV battery charge state
- Inside temperature and humidity
- GPS location
I'll add to this as I work on this project over time. I already have the first few new things I'll add:
- Bump detection if someone hits or climbs aboard
- PIR intrusion detection
- Motion-activated image capture and forwarding camera
Below is a diagram of the overall monitoring system. There is quite a bit to it so I will take it one step at a time. It is all pretty modular so it is easy to construct just the parts you might be interested in. First steps are getting the starter kit up and running and going through a couple of the tutorials. If you are comfortable with the hardware, already know about AT&T M2X, Flow, and mbed then you could skip to the “Power supply and voltage monitoring” section.
Below is a picture of my completed device ready to install out at our Airstream. Notice the Xadow GPS and Adafruit temperature and humidity boards connected via modular phone wire. It was a handy way to make interchangeable sensor connections.
Below is a picture of a Raspberry Pi 3 connected to the standard 7" touch screen display showing the data being updated from the monitoring system. It sites on the bookshelf in our living room where we can keep an eagle on on our Airstream some 10 miles away in the RV storage area.
Step one is to get familiar with the AT&T IoT Starter Kit. It is a remarkably capable device even just as it comes. The parts list shows where you can purchase one. It comes with every thing you need to get started. Although it might seem a bit pricey at $99, this device is great! It’s packaged with the mbed FRDM-K64F that is an Arduino shield pin compatible board running the very capable embed RTOS. It’s mated with the Avnet WNC cellular modem shield to connect to the LTE cellular network. Along with it is an AT&T data SIM card that comes with a pretty generous 300MB of data to get started. When the box comes, it is important to assemble it following the “Quickstart” page. The kit comes with a printed quick start card listing 13 steps. I recommend *not* using this but instead, going through the complete “Getting Started Guide” I've indicated above as it will take you through some additional helpful steps and more detailed explanations. If you are a mostly hardware person like I am, then going though the entire guide is a must. Don’t forget to update the WNC cellular shield firmware at the link on that page! Go all the way through the “Getting Started Guide”. This 48 page guide might seem daunting but it’s detailed, pretty straight forward. At the end you will have a complete end to end system going all the way through creating accounts at mbed, AT&T Starter Kit, M2X, and Flow. This will get data from the onboard sensors to AT&T's M2X data charting service and introduce you to Flow and the bed compiler. This forms the basis for the rest of this project. I won’t take up any space going through those steps but will assume you have completed it before moving on.
Add a GPS
Next add the Seed Studio GPS board using this starter kit tutorial. There a many different small GPS units available however I chose to stick with the Seeed Xadow since all the difficult software bits were already done. It uses an I2C interface which works will for short cable distances, typically up to about a meter depending a lot on the noise environment and speed of data communications. Again, to get the system up and running in our Airstream I stuck with this unit. Once completing this tutorial the system will be able to report GPS data plus temperature and humidity from the HTS221 sensor onboard the WNC shield.
I took this breadboarded system out to our Airstream just to make sure I could receive a good LTE signal and GPS location fix with the cellular blade antennas and Xadow GPS next to the window. Worked great! You can see it pictured here taped under the cabinet powered by auxiliary USB battery. The device with the blue glowing display monitors voltage and current on the USB port. More about power later. On to the next steps!
The HTS221 temperature and humidity sensor mounted to the WNC shield is convenient, but it turns out it seems to be affected by heat from the board electronics quite a bit. Plus, once mounted in a case, it won’t sense the ambient conditions very well. I wanted something a bit more accurate. There is a starter kit tutorial showing how to add a Silicon Labs SENSOR-PMOD board. Unfortunately, when I first started, it was not available. After contacting the folks at Avnet they discovered they had them in stock, just not available for sale at the time. Well, now they are now available through www.avnet.com as part number AES-PMOD-SENSOR1-SIL-G. The good news for me at the time was that Adafruit has a breakout board using the almost identical Silicon Labs Si7021 sensor. With one small change to the mbed sensor.cpp file, it is a drop in change for the SENSOR-PMOD temperature and humidity board. The only change needed was to modify the mbed Avnet_ATT_Cellular_IO sensor.cpp file changing its I2C ID from hex 0x14 to 0x15 and it worked! The Adafruit board does not have the proximity and light sensor but other than that it works well, and was just what I needed. Hackers then have a choice of either ordering the PMOD sensor board from Avnet or using the Adafruit board I am using (and is what I've listed in the parts list). Once you have either board, follow the PMOD Sensor tutorial to get it up and running wth the starter kit. Initially I disconnected the Xadow GPS and connected just the Adafruit (or Silicon labs PMOD sensor if you prefer) to make sure everything worked as specified in the tutorial.
Power supply and voltage monitoringThe next step is RV battery monitoring. What follows is a pretty long discussion on power requirements and design. If it’s too long, feel free to skip over down to the power supply circuit.
Typically when in long term storage RV trailer owners, like me, physically disconnect the battery, and if it is really cold, remove it and bring it someplace where a trickle charger can keep it healthy. Fortunately our Airstream is equipped with 160 watts of solar panels, so we keep our battery installed and connected. Generally this is sufficient insurance against killing the dual deep-discharge batteries. But, if there is a long string of cloudy days, or the panels get covered with snow, the batteries may slowly die before we have the chance to get out there and check on them. We can prevent this by remotely monitoring the battery voltage. If it starts to get low, I can head out and clean off the solar panels, or perhaps disconnect the battery.
For this project, I also want to power the monitoring system from these same RV batteries. Thus I needed to create a 5 volt source from the nominally 12v RV battery supply. Even with solar panels, power management while the RV is unattended is an issue for the reasons I described above. Our dual batteries each have an 84 amp-hour rating for a total of 168 amp-hours of capacity with the two connected in parallel. The Airstream has an electronic battery disconnect that mostly separates battery power from the the rest of the system that is supposed to be used when storing. I say "mostly" because there is still a couple battery vampires connected even after actuating the disconnect. The solar power management system and a gas vapor alarm remain connected, and cannot be turned off. Together these consume an average of about 200 milliamps of current. I measured this with a clamp on current meter. This measurement may have some inaccuracies, but for me it is enough for some back-of-the-envelope calculations. If the solar panels were somehow completely covered (like with snow for example) we can get a rough idea how long the batteries should last.
168 Ah / 0.2 A = 840 hours / 24 hours/day = 35 days
Thus our batteries should last about a month with no sunlight before adding our monitoring system. Of course this will vary a lot depending on temperature and charge state, but it is at least a starting point.
Time to take a look at the power needed if we add our Mobile Life IoT monitoring system. Let’s find out how much power the starter kit uses. Initially I monitored the average usage with a USB voltage and monitoring dongle. There are several available, the one I used came from Newegg for $5 but there are many out there. This showed the starter kit, with GPS and temperature boards connected, using about 200 milliamps on average, with some variations. Although not super accurate, this is enough to show that adding the monitoring system to my existing RV system would probably drop the time-to-kill-the-batteries-without-solar to a couple weeks:
168 Ah / ( 0.2 A (monitoring system) + 0.2 A (existing drain) ) = 420 hours / 24 hours/day = 17.5 days
Since our solar panels can provide "up to" 160 watts, I could theoretically get up to 12 - 15 amps of charge current. In practice I have only ever seen 6 amps maximum. Even so, given sunlight, and as long as I get out to clean of any snow accumulation on the panels within two weeks, power should last indefinitely. But, we’re not finished yet. This is average power, we need to power the starter kit even at peak usage which typically occurs when the LTE modem is communicating with the cellular network. What does this profile look like? The starter kit documentation recommends a 2 A 5v supply and also notes the worst case modem power usage at 800 mA. I wanted to see what this looked like so I connected the positive supply through a 1 ohm, 0.5 watt resistor and connected one to the analog inputs of Sparkfun’s Logmatic data loggers. I then captured and plotted the current usage profile in Excel:
You can see that the current usage hops around quite a bit with the sharp peaks occurring as the LTE modem reaches out to send data. The data shows that indeed the modem current usage peaks at around 700 mA, just a bit lower than the starter kit guide says, but pretty close. This helps in the design of our mobile power supply system. It needs to provide a continuous average current of 200 mA with peaks surging up to a bit over 700 mA. I considered using a straight 7805 linear regulator but the inefficiencies bothered me. The starter kit consumes about 1 watt of power ( 5 volts x 0.2 amps). A 7805 design would required to supply at least 1 amp, and really 1.5 amps to be safe. At 200 mA average power the 7805 itself would be using (InputVoltage - 5V) * AverageCurrentInAmps or in our case:
(13.5v - 5v) * 0.2A = 1.7 watts lost to heat!
In this case our input power is 13.5v * 0.2A = 2.7 watts while our output power is 5v * 0.2A = 1 watt. The efficiency if we used a 7805 would then be:
Pout / Pin = 1w / 2.7w = 0.37 or 37%
Yikes! Not too good especially when we are trying to conserve as much battery as possible over the long haul. We can boost this efficiency enormously by switching to a DC-to-DC switching converter. There are several 7805 pin compatible units for sale. I’ve used products from Dimension Engineering for several years with good luck, so I opted to use their DE-SW050 5volt, 1.5amp device. Going by the graph in their data sheet we should get somewhere around 80% to 85% efficiency. Much better, and well worth the $15.
Next we turn to measuring the battery voltage with our starter kit hardware. For this we will use one of the Analog to Digital Converters (ADC) on the mbed FRDMK64F board. It took a bit of sleuthing through the mbed documentation and schematics to find an available GPIO pin that could map to one of the board’s ADC’s. Looking at the starter kit documentation shows that pretty much all of the Arduino shield compatible pins are already dedicated and thus not available. Fortunately the FRDMK64F connectors have a second row of pins for use. I chose J1-11 on the mbed FRDMK64F board which maps to PTC0/ADC0_SE14 ARM processor pin. The FRDMK64F processor's ADC measures input from 0 to 3.3 volts. Therefore I needed a voltage divider to step the RV battery voltage down to within this range. I figure the most voltage I will need to measure is probably around 16 volts but just to be sure, and also to be able to use standard resistor values, I chose 4.7k ohm and 22k ohm to form a divider circuit that will measure up to 18.75 volts. Once constructed, I used a variable power supply and a voltmeter to calibrate the voltage measurements. More on this later. Below is the schematic for the power supply and voltage divider.
You can see the DE-SW050 voltage regulator that provides the 5 volt power to the starter kit and the voltage divider formed by R1 and R2 for measuring the RV battery voltage. R3 is a current limiter in case the battery input voltage gets a bit out of hand. The two Schottky diodes serve as voltage clamps for additional protection of the ADC input. Capacitors C1 and C2 help filter any ripple and noise coming from the battery supply. Finally C3 helps keep the ADC voltage input well behaved by filtering any noise that might have slipped through. I recommend breadboarding the circuit first to ensure everything is working.
The values for C1 and C2 are not critical and can be anything from 10uf to 100uf. The important thing is that the voltage ratings of these capacitors be high enough. I recommend a voltage value of at least 35 volts. Once fully breadboarded, connect the 12v battery connections to a supply that is somewhere between 7 and 15 volts. Then confirm that the output at the orange 5v terminal is indeed 5 volts and the voltage at R3 is between 0 and 3.3 volts.
Breadboard the full projectNext it’s time to connect everything together and test out the full circuit. Below is a diagram of the full project.
There are a few things to note about the diagram right off the bat. First of all, I’ve included a not-yet-implimented PIR sensor in the configuration. So far, I have not had a chance to work out the software part of this. I have, however, identified an appropriate pin on the FRDMK64F board (J1-9 going to GPIO PTC9 as shown) for it, and connected it up, but that’s as far as I’ve gotten with that sensor. The other thing to note is that in the diagram I have both the Xadow and Si7021 connected in parallel to the PMOD connector on the WNC shield. This is the way I have it wired in my final project. However, for convenience while breadboarding, I took advantage of the fact that the I2C SDA and SCL lines are replicated on the WNC shield’s connectors, specifically the WNC shield J4 pins 5 and 6 respectively. Also, extra ground and 3.3v connections are available on J3 pins 7 and 4 respectively. I used these pins during the breadboarding phase to connect the Xadow GPS and the PMOD connector for the Si7021 board.
Next, after you have confirmed the correct voltage levels from your power breadboard (see above), its time to connect up the power breadboard to the project. Make sure you get these next connections correct, mistakes will likely result in frying the WNC shield:
Power Board WNC Shield pin
Ground (black) J3 - 6
5v (red) J3 - 8
3.3 (green) J3 - 2
Beware, I am powering the starter kit via the 5v Vin pin (shown as VIN_H_5V0 on the WNC shield schematic). Although this is convenient, as puts the 5 volt power to the right places, it bypasses all of the WNC shield’s protective circuitry! It would be better to go through the USB connector, but with a USB cable plugged in, the starter kit would not fit in the case I selected. So, I’ve taken a slightly more risky route. If you have the space, I would recommend cutting of the end of a spare USB cable and wiring the power board’s 5 volt and ground wires to the red and black wires of the USB cable and plugging that into the WNC shield just as you would the normal power connection. That would preserve the additional protection of WNC shield's circuit.
The final power board connection is the yellow voltage monitoring wire coming from the resistor divider network. This has to connect to the secondary row of connections on the mbed board underneath the WNC shield: FRDMK64F J1-11. This row of connections is hidden when the shiled is installed. To solve this I first separated the two boards carefully...it is easy to bend the pins, I know from experience. Next break off a row of 8 90-degree header pins like these from SparkFun. Plug the short side into the inner row of bed J1 then connect the voltage monitor wire (yellow) to it. The WNC shield can then be plugged back in. See the below picture below.
Once the WNC shield is installed back on top of the bed FRDMK64F board and all wires connected your breadboard kit should look something like the below picture.
Getting to this point I will assume you have gone through the "Getting Started With IoT Starter Kit”, the "Cellular Shield Firmware Upgrade”, as well as the two tutorials, "Extending the Starter Kit Project With The Xadow GPS Module” and "Extending the Starter Kit Project With The Silicon Labs PMOD Sensor”. If you haven’t yet then please do. I will go through the changes I made to those base software examples so it is important that you have those working first.
Changes to the mbed projectThis is the software loaded on to your IoT device. It is the heart of the system as it talks to all of the sensors, gathers the data and posts it to the cloud over the cellular network. It is all built on top of the very capable mbed RTOS and uses the WNC shield libraries as is. Here are the changes I’ve made to the Avnet_ATT_Cellular_IOT project from the starter kit Getting Started tutorial. I am going to step through all the changes I made to the base project. If you would rather, you can clone my mbed ATT_Cellular_Mobile_Life_IOT_Public project directly by selecting the "Import into compiler". You then only need update the config_me.h with your base URL. If you prefer to start from the Might be a good idea to start by renaming the project to keep it separated from the original. For example, I’ve renamed mine “ATT_Cellular_Mobile_Life_IOT”. You can check out the files from my GitHub if you would like. Theoretically you would just have to put in your own base URL and it should work. However, you will probably have a lot less headache if you make the changes to your own project item by item as I go through them below. I’ve only modified a few of the files from the original project you should have at the finish of the starter kit tutorial. Here are the only files in the project I have changed:
- config_meh.h
- sensors.h
- sensors.cpp
- main.cpp
config_meh.h: This file should already have your base urI entered from when you completed the starter kit tutorial. The other changes I made were:
- renaming the FLOW_INPUT_NAME from “climate” to “status” just because it better reflects the contents of the stream
- renaming the device to “mobilelife001” to personalize it a bit
- changed the stream update interval to 30 seconds to reduce the data usage
- changed the sensors to report to match our new sensor configuration
The file is pretty short so you can look through and find these parameters to change:
// These are FLOW fields from the Endpoints tab:
#define FLOW_BASE_URL "/your_flow_base_url_here/in/flow"
#define FLOW_INPUT_NAME "/status"
// Unless you want to use a different protocol, this field should be left as is:
#define FLOW_URL_TYPE " HTTP/1.1\r\nHost: "
// This identifier specifies with which FLOW device you are communicating.
// If you only have one devive there then you can just leave this as is.
// Once your FLOW device has been initialized (Virtual Device Initialize clicked),
// the Virtual Device will show up in M2X. This is its "DEVICE SERIAL" field
#define FLOW_DEVICE_NAME "mobilelife001"
// This constant defines how often sensors are read and sent up to FLOW
#define SENSOR_UPDATE_INTERVAL_MS 30000; //30 seconds
#define SHIELDTEMP_ACCELEROMETER_BATTERY 1
#define SHIELDTEMP_ACCELEROMETER_BATTERY_INTRUSION 2
#define SHIELDTEMP_ACCELEROMETER_BATTERY_GPS 3
#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP 4
#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS 5
#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION 6
static int iSensorsToReport = SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION; //modify this to change your selection
sensors.h: Next let's look at changes to the header file for the sensors.cpp. Here is another pretty short file. Here is a summary of the changes I've made:
- got ride of the virtual sensors USB interface. I have no intention of using these and it cluttered up the sensor code quite a bit.
- added the voltage and intrusion data fields to the K64F_Sensors_t data structure.
- added a celsius to Fahrenheit conversion definition. The compiler complained a bit when I did it this way but still seems to work OK.
Again, the file is pretty short so you can pretty easily compare to this listing and make the changes manually, or just copy the whole thing as is:
#ifndef __SENSORS_H_
#define __SENSORS_H_
void sensors_init(void);
void read_sensors(void);
#define CTOF(x) ((x)*1.8+32)
#define SENSOR_FIELD_LEN_LIMIT 32
typedef struct
{
char Temperature[SENSOR_FIELD_LEN_LIMIT];
char Humidity[SENSOR_FIELD_LEN_LIMIT];
char AccelX[SENSOR_FIELD_LEN_LIMIT];
char AccelY[SENSOR_FIELD_LEN_LIMIT];
char AccelZ[SENSOR_FIELD_LEN_LIMIT];
char MagnetometerX[SENSOR_FIELD_LEN_LIMIT];
char MagnetometerY[SENSOR_FIELD_LEN_LIMIT];
char MagnetometerZ[SENSOR_FIELD_LEN_LIMIT];
char Temperature_Si7020[SENSOR_FIELD_LEN_LIMIT];
char Humidity_Si7020[SENSOR_FIELD_LEN_LIMIT];
char GPS_Satellites[SENSOR_FIELD_LEN_LIMIT];
char GPS_Latitude[SENSOR_FIELD_LEN_LIMIT];
char GPS_Longitude[SENSOR_FIELD_LEN_LIMIT];
char GPS_Altitude[SENSOR_FIELD_LEN_LIMIT];
char GPS_Speed[SENSOR_FIELD_LEN_LIMIT];
char GPS_Course[SENSOR_FIELD_LEN_LIMIT];
char Battery_Voltage [SENSOR_FIELD_LEN_LIMIT];
char Intrusion_Detected [SENSOR_FIELD_LEN_LIMIT];
} K64F_Sensors_t ;
extern K64F_Sensors_t SENSOR_DATA;
#endif
sensors.cpp: Now that we've done the header file, it's time to modify the sensor.cpp file. Here’s the part where we initialize and read the data from all the sensors. Changes to this file are:
- added the analog read for the battery voltage sensor
- changed the Si7020 sensor id from 0x14 to 0x15 to detect the Si7021.
- removed the virtual sensor code
One mode would be to replace the sensors.cpp file in your project with the one from my GitHub project however, I’ll go over each of the changes here.
Just before the “Perform I2C singe read” comment section add these to lines. The provide the calibration factor for the voltage sensor divider (we’ll calibrate this later) and the initialization of the analog pin:
#define VOLTS_SCALE 18.6 //scale battery voltage measurement based on R1 and R2
AnalogIn Analog0(PTC0); // Had to use J1-11 for PTC0 to deconflict from wnc shield pins
Next add in the method that will read in the the analog voltage data. I put this right after the I2C write section, after the comment that is "//I2C_WriteMultipleBytes()” and before the “Init_Si7020" method:
//***************************************************
//* Battery Voltage
//***************************************************
void Read_Battery_Volts(void)
{
float Volts;
Volts = Analog0 * VOLTS_SCALE;
PRINTF("Voltage: %0.3f Volts \r\n", Volts);
sprintf(SENSOR_DATA.Battery_Voltage, "%0.2f", Volts);
}
This snippet takes a reading, "Analog0" from the analog pin PTC0 initialed earlier. The value is a float from 0 to 1 corresponding to 0 to 3.3 volts. It is then scaled by multiplying time the “VOLTS_SCALE” value. The "VOLTS_SCALE" value will be slightly different depending on the particular values for R1 and R2 in the voltage divider network but should be somewhere around 18.6 as mine is. Once finished, tweak this value up or down to obtain accurate voltage readings.
Next it’s time to change the Si7020 code to identify the Si7021 assuming you are using the Adafruit board. If, instead you are using the Avnet SENSOR-PMOD board then ignore this change. If you are using the Adafruit board equipped with the Si7021 sensor then look just a few lines further down for the “if” statement that says:
- if (SN_7020[4] != 0x14)
Leave this as is for the SENSOR-PMOD board but, if using the Adafruit board with the Si7021, change the 0x15 to 0x15 like the following:
- if (SN_7020[4] != 0x15) //Si7021 this is 0x15, for Si7020 this is 0x14
Now that we’ve added a new sensor, the analog pin, we have to change the read_sensors routine to get it’s value. Go all the way to the bottom of the sensors.cpp file and look for the "void read_sensors(void)” line. Change this method to add the Read_Battery_Voltage() :
I also made a small change to the Xadow GPS section. As written, the device will wait until the GPS is locked onto enough satellites for a valid reading before sending any data from any of the sensors. I did not want block execution waiting for a GPS lock so I commented out this section. The side effect is that the GPS will report a lat/lon position of 0/0 until it finds enough satellites for a lock. Turns out this is a position in the Atlantic off the coast of Africa! Later on I plan to do something a bit more clever but for now it is fine. If you wish to make the same change, look for the line with the comment that says:
- { //we must wait for GPS to initialize
then comment out that entire if statement so it looks like this:
/* rather not wait for valid GPS before reporting sensors
if ((status != 'A') && (iSensorsToReport == TEMP_HUMIDITY_ACCELEROMETER_GPS))
{ //we must wait for GPS to initialize
PRINTF("Waiting for GPS to become ready... ");
while (status != 'A')
{
wait (5.0);
status = gps_get_status();
unsigned char num_satellites = gps_get_sate_in_veiw();
PRINTF("%c%d", status, num_satellites);
}
PRINTF("\r\n");
} //we must wait for GPS to initialize
*/
The next changes I made were just to remove stuff I am no longer using like all of the virtual sensor code and the code to read the Si1145 sensor. You can probably leave this in, particularly the Si1145 code if you happen to be using the SENSOR-PMOD board. To delete the Si1145 code:
Start at the comment that says:
- * The following are aliases so that the Si1145 coding examples can be used as-is.
and delete all the way down to the commented line that says:
- } //Read_Si1145()
To delete the virtual sensor code scroll down to the line:
- #ifdef USE_VIRTUAL_SENSORS
and delete the code within that “ifdef”. If you do delete it, then don’t forget to also delete the one line within the short “#ifdef USE_VIRTUAL_SENSORS” in the “sensors_init” method. Of course, there is no real harm in leaving it in, it just makes more difficult to find the bits that or of interest.
main.cpp: Like with the sensors.cpp file, you could just copy the one from the project GitHub. However, I will go through each of the changes I’ve made here so you can make them manually if you prefer. The changes are to add the new sensor data lineup and then make sure the string that is sent to the modem is our “status” message that matches what we asked for in the config_meh.h file. Lots of tricky string formulation. It is important as this must match what we will be expecting when we get to the AT&T Flow portion.
The first change is to make the SENSOR_DATA string match our sensors.h. Look for the "K64F_Sensors_t SENSOR_DATA” sensor string variable declaration and replace it with this:
//******************************************************************************
//* Create string with sensor readings that can be sent to flow as an HTTP get
//******************************************************************************
K64F_Sensors_t SENSOR_DATA =
{
.Temperature = "0",
.Humidity = "0",
.AccelX = "0",
.AccelY = "0",
.AccelZ = "0",
.MagnetometerX = "0",
.MagnetometerY = "0",
.MagnetometerZ = "0",
.Temperature_Si7020 = "0",
.Humidity_Si7020 = "0",
.GPS_Satellites = "0",
.GPS_Latitude = "0",
.GPS_Longitude = "0",
.GPS_Altitude = "0",
.GPS_Speed = "0",
.GPS_Course = "0",
.Battery_Voltage = "0",
.Intrusion_Detected = "0"
};
Next look for the “GenerateModemString” function and replace it with this:
void GenerateModemString(char * modem_string)
{
switch(iSensorsToReport)
{
case SHIELDTEMP_ACCELEROMETER_BATTERY:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
case SHIELDTEMP_ACCELEROMETER_BATTERY_INTRUSION:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&intrusion=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Intrusion_Detected, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
case SHIELDTEMP_ACCELEROMETER_BATTERY_GPS:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION:
{
sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s&intrusion=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, SENSOR_DATA.Intrusion_Detected, FLOW_URL_TYPE, MY_SERVER_URL);
break;
}
default:
{
sprintf(modem_string, "Invalid sensor selected\r\n\r\n");
break;
}
} //switch(iSensorsToReport)
} //GenerateModemString
Notice these case statements match the “iSensorsToReport” declaration in the config_meh.h file. Between this and the sensors.cpp you can manipulate exactly what data you wish to send.
Pro Tip: While getting everything up and running on the mbed board, it is time consuming to wait for the WNC shield to initialize the modem and send the data, plus it uses up data when maybe you would rather not. It is easy to comment out the parts of the main.cpp the deal with the modem, then recompile and load. If you wish to do this, then comment out these two sections. I use the “TODO” markers so I can easily track these sections down with a search if I need to:
//TODO: comment out these next two lines for local testing (no modem send) to keep from initializing the modem
cell_modem_init();
display_wnc_firmware_rev();
and this part:
// TODO: comment out to the next "TODO" for local testing to keep from sendng to modem
char myJsonResponse[512];
if (cell_modem_Sendreceive(&modem_string[0], &myJsonResponse[0]))
{
if (!ledOnce)
{
ledOnce = 1;
SetLedColor(0x2); //Green
}
parse_JSON(&myJsonResponse[0]);
}
// TODO: end testing comment out section
Once all these changes are made to you project on in the online mbed compiler, it’s time to compile and load it onto your project as you have done during the tutorials. Assuming everything is correct, open up the serial connection and look for an output that should look something like:
App Firmware: Release 1.0 - built: Jan 18 2017 13:03:03
Hello World from the Cellular IoT Kit!
HTS221 Detected
Temp is: 63.83 F
Humid is: 30 %
Si7020 SN = 0x78411C3215FFB5FF
Si7020 Version# = 0x20
FXOS8700CQ WhoAmI = C7
Xadow GPS Scan ID response = 0x0004 (length), 0x00000005
gps_check_online is 1
gps_get_utc_date_time : 17-2-1,2:11:30
gps_get_status : A ('A' = Valid, 'V' = Invalid)
gps_get_latitude : N:38.927528
gps_get_longitude : W:77.232094
gps_get_altitude : 155.529999 meters
gps_get_speed : 0.246000 knots
gps_get_course : 119.000000 degrees
gps_get_position_fix : 2
gps_get_sate_in_view : 12 satellites
gps_get_sate_used : 8
gps_get_mode : A ('A' = Automatic, 'M' = Manual)
gps_get_mode2 : 3 ('1' = no fix, '1' = 2D fix, '3' = 3D fix)
Voltage: 13.759 Volts
HTS221 Temp is: 63.8 F
HTS221 Humid is: 30 %
Si7020 Humidity = 44.9 %
Si7020 Temperature = 48.9 deg F
Acc: X=0.019 Y=0.184 Z=0.968;
gps_satellites : 12
gps_get_latitude : 38.927528
gps_get_longitude : -77.232094
gps_get_altitude : 155.529999 meters
gps_get_speed : 0.246000 knots
gps_get_course : 119.000000 degrees
Modem initializing... will take up to 60 seconds
Followed by a lot of handshaking with the modem if you haven't commented it out. Also, the GPS data will probably be all zeros until it runs for awhile.
Next I will go over the changes I made to the AT&T Flow example for using our new parameters, connection to PubNub and a webpage to display the data using PubNub’s EON charting and mapping leveraging the beautiful capabilities of C3js.org and MapBox.com. For viewing status, I host a website using Amazon AWS Route53 and their S3 storage with my html and javascript webpage.
Configuring AT&T M2X and FlowI am primarily a hardware guy. So walking through the details of the software on the cloud based services for this project was my biggest learning curve. For those readers adept in this area, bare with me as I trundle through. Getting all this part working was the most challenging. A misplaced comma, or using a curly brace instead of a square brace can take awhile to figure out. My method was similar to what I did with the mbed software--start with the provided working example and expand it. The best way to get going here is to make sure you work through the AT&T IoT Starter Kit Getting Started Guide as I said at the beginning of this software section. Thus you should have your device's SIM card activated and the mbed software modified to support the new sensor configurations. The AT&T Flow Starter Kit Reference Project is the basis for what I did for the this project. The easiest way to get going is to find the Mobile Life IoT Public project I've place in the Flow community list and "fork" it. This will give you the full Flow project with the nodes already configured to read the new sensor parameters you configured in the mbed software above. Remember you will have to configure your forked project with your own M2X account key just like you did in the tutorial reference project. On your forked Mobile Life project that shows up in the same location on the "Data" tab as in the figure below.
You will also have new endpoints to insert just as you did in the tutorial. There is a number of fiddly bits that the tutorial takes you through. Since I've kept the project very similar, you should be able to follow it and match up. I've simplified some of the Flow nodes in the Mobile Life version and you will note that instead of "/climate" in the left end point source I've changes it to a more appropriate "/status" in the HTTP Get node on the Data tab. This must match the /status in the mbed software from the above section. You can also see I've taken out all the heat index and other climate related nodes that are in the tutorial so the project simply now gets the status message from the IoT device, does some basic formatting, divides it up into a "status" and "location" stream, and then publishes it to PubNub. You can see those nodes in the diagram below:
Once deployed you can select "debug" in the low window and, if all is well you should see data flowing from your device to the debug nodes.
If not, double check that you have the M2X key saved in the "Configuration" node and the "Endpoints" saved in your mbed code as was done in the tutorial. You man have to perform the one time initialization with the "initialize inject" node on the "Virtual Device" tab, this gets M2X configured to listen for your messages. Another place to look is on the mbed serial USB console, also as described in the tutorial. You should see something like in this window that repeats every 30 seconds:
Sensor readings...
Voltage: 13.795 Volts
HTS221 Temp is: 66.2 F
HTS221 Humid is: 26 %
Si7020 Humidity = 42.3 %
Si7020 Temperature = 47.6 deg F
Acc: X=0.080 Y=0.188 Z=0.963;
gps_satellites : 11
gps_get_latitude : 3855.654785
gps_get_longitude : -77.232361
gps_get_altitude : 160.399994 meters
gps_get_speed : 0.240000 knots
gps_get_course : 207.600006 degrees
...end sensor readings
GET /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/in/flow/status?serial=mobilelife001&temp=66.2&humidity=26&accelX=0.080&accelY=0.188&accelZ=0.963&batt_volt=13.79&temp2=47.6&humidity2=42.3&gps_satellites=11&latitude=3855.654785&longitude=-7713.941895&altitude=160.399994&speed=0.300000&course=207.600006&intrusion=0 HTTP/1.1
Host: run-east.att.io
Sending to modem : GET /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/in/flow/status?serial=mobilelife001&temp=66.2&humidity=26&accelX=0.080&accelY=0.188&accelZ=0.963&batt_volt=13.79&temp2=47.6&humidity2=42.3&gps_satellites=11&latitude=3855.654785&longitude=-7713.941895&altitude=160.399994&speed=0.300000&course=207.600006&intrusion=0 HTTP/1.1
Host: run-east.att.io
Send: <<AT+CSQ>>
[AT+CSQ+CSQ: 16,99OK]
Send: <<AT+CPIN?>>
[AT+CPIN?+CPIN: READYOK]
Send: <<AT+CREG?>>
[AT+CREG?+CREG: 2,1,1211,0A0F6409,7OK]
Send: <<AT@SOCKDIAL?>>
[AT@SOCKDIAL?@SOCKDIAL:1OK]
Send: <<AT@SOCKWRITE=1,350,"12345678901234567890...>>
[AT@SOCKWRITE=1,350,"12345678901234567890...]
Send: <<AT+CSQ>>
[AT+CSQ+CSQ: 16,7OK]
Send: <<AT+CPIN?>>
[AT+CPIN?+CPIN: READYOK]
Send: <<AT+CREG?>>
[AT+CREG?+CREG: 2,1,1211,0A0F6409,7OK]
Send: <<AT@SOCKDIAL?>>
[AT@SOCKDIAL?@SOCKDIAL:1OK]
Send: <<AT@SOCKREAD=1,1024>>
[AT@SOCKREAD=1,1024@SOCKREAD:427,"12345678901234567890...]
Send: <<AT+CSQ>>
[AT+CSQ+CSQ: 13,7OK]
Send: <<AT+CPIN?>>
[AT+CPIN?+CPIN: READYOK]
Send: <<AT+CREG?>>
[AT+CREG?+CREG: 2,1,1211,0A0F6409,7OK]
Send: <<AT@SOCKDIAL?>>
[AT@SOCKDIAL?@SOCKDIAL:1OK]
Send: <<AT@SOCKREAD=1,1024>>
[AT@SOCKREAD=1,1024@SOCKREAD:0,""OK]
Read back : HTTP/1.1 202 Accepted
X-Powered-By: Express
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Content-Length: 21
ETag: W/"15-GAf/odROZnWSoPkcZoumWw"
set-cookie: connect.sid=s%3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Path=/; HttpOnly
Date: Sun, 29 Jan 2017 20:30:57 GMT
Connection: keep-alive
{"status":"accepted"}
JSON : {"status":"accepted"}
Notice the "JSON : {"status":"accepted"} " as the last line of each. This means everything is working.
PubNub and MapBox connectionNext we are going to feed our data to PubNub. It is a good idea to go through the AT&T starter kit PubNub integration tutorial. This will get familiarity with PubNub and get an account setup. You will need the PubNub publish and subscribe keys to put into the appropriate nodes in the Flow project. Go to the PubNub account page and copy the publish and subscribe keys one at a time:
Then in the AT&T Flow project screen double click the "status PubNub out" node and paste each of the publish and subscribe keys as shown below:
Then close the edit dialog and select the "Deploy" button in the upper right corner to save and run the changes. The publish and subscribe keys are also needed in the "location" PubNub out node but I've found that Flow is smart enough to automatically populate it with the keys. Although it is a good idea to double click that node as well and confirm your keys are there. Now the status and location data streams should be flowing to PubNub. Confirm this by opening the PubNub debug console opened by selecting the "Debug" tab in the lower right of your PubNub account page. Enter "status" in the channel field and anything you would like in the UUID field, for example, "UUID-Test". Then select, "Add Client". The status messages should begin appearing in the debug console:
There are a lot of really cool things you can do with data and PubNub. For this project we are going to use the really slick charting functions they've enabled with their PubNub Eon integration. There are three charting and graphing functions we'll use, the gauge function, the spline graph, and finally, mapping location using the one marker map function. One more account is needed to enable the mapping function. The folks at MapBox.com provide a great mapping service. Once you've created a MapBox account you will need to get a MapBox ID and token for the map you wish to use for your Eon mapping. The trick is that you have to use the MapBox "classic" map for this. You will see a link to it in the lower left side of your MapBox account page. This also means you will have to download and install MapBox Studio Classic. I chose the "comic" style map just because it was a bit different. There are many map styles to choose from. Once you've got a and ID and token for your map it's time to create the monitoring webpage!
Mobile Life WebpageBelow is a screen shot of the webpage. The full HTML / Javascript is included in the attachments.
The next step is to host your website somewhere. One good place would be Amazon Web Services. After creating an AWS account, use the services to register your domain name. There are straightforward tutorials to help you along with this. You can then upload the .html file to your AWS S3 bucket linked to your domain name and now you can monitor the status from anywhere!
Hardware FinishYou may have your own ideas on how to enclose and mount your mobile monitoring system. Below are some ideas about how I went about it. Everything fit in a Vellman WCAH2853 project box nicely. I wanted to have a way to quickly connect and disconnect sensor and practice some interchangeability. To do this I decided to try use modular phone connectors and sockets. I know the I2C interface is not made to travel far, so I kept my modular phone line lengths to less than a meter. So far it is working well. Here are some photos of my assembly steps:
I feel much better now that I can keep track of status of our Airstream from anywhere. The website displays well on pretty much any device, and in any browser. I've got it displayed on a Raspberry Pi 3 connected to a 7" display showing the status webpage in kiosk mode in our living room. We can now easily keep an eye on things while sitting around watching TV, or chatting with family and friends.
The PubNub Eon charts and maps made it easy even for a a web services neophyte like me to to make a great looking display. The confluence of great hardware from mbed, AT&T, Avnet, Seed and Adafruit along with the amazing cloud services including AT&T Flow, PubNub Eon, and MapBox make for a truly remarkable environment for doing incredible things! Please feel free to contact me if you have and questions or suggestions.
Comments