S3A7 Home Temperature and Humidity Monitor with Mobile Access

s3a7

#1

Home Temperature and Humidity Monitor with Mobile Access

This project turns your S3A7 IoT sandbox into a home temperature and humidity monitor that you can access with the Medium One mobile app. The system records the ambient temperature and humidity at an interval you define in code. After a specified number of readings, the data are emailed to you. At any time, you can use the mobile app to request an instantaneous temperature reading which is pushed to your mobile device.

This project is a cleaner more refined version of the original Home Temperature Monitor. It adds humidity to the data logging functionality, and it adds the ability to take a real time temperature reading using the mobile app. It still uses the S3A7 board with Smart Chef code in memory, but this is a new project created from scratch. It is intended as a second or third project and it assumes that you know how to activate tags, create new workflows and add various triggers and outputs to workflows.

In this tutorial you will:

  • Create a new project
  • Create new workflows
  • Create and activate new tags
  • Customize different types of workflow triggers
  • Utilize the Renesas ‘Store’ Library to save information
  • Configure and use the Renesas Mobile App
  • Utilize the FCM library to send push notifications

Step 1: Complete the Smart Chef Demo

You will create a new project with a new API user/key unique to this project. The Smart Chef demo shows you how to do this. You learn how to start the board in provisioning mode and get it connected to the internet. After completing the tutorial, you’ll repeat that process for our new project.

The Smart Chef tutorial is located here: http://renesas-blog.mediumone.com/renesas-s3a7-fast-iot-prototyping-kit-with-smart-chef-demo-quick-start-guide/

Step 2: Complete the Renesas IoT Sandbox Mobile App Quick Start Guide

If you did not complete the installation of the mobile app in the previous step, this guide shows you how to do it. For the temperature and humidity monitor you will need the Medium One mobile app on your phone. Either ios or Android devices will work. The quick start guide shows you how to configure the app with the new API key you create for this project.

The quick start guide is located here:
http://renesas-blog.mediumone.com/renesas-iot-sandbox-mobile-app-quick-start-guide/

Step 3: Create a New Project in IoT Sanbox

This link leads you to the following screen where you can create a new project:
https://mediumone.com/partner/activate-rna.php?partner=renesas&boardtype=s3a7&kit=s3a7

Fill in your information and click ‘Activate!’ Be sure to specify a new unique name for the project. You may use the same email that you used to activate your account in the Smart Chef demo. After activating, you will receive an email with your MQTT IDs, API key, API password etc. Those credentials will allow you to configure the IoT board with the new project API key etc., just as you did in the Smart Chef demo.

Once you have the IoT board provisioned with the new API key and connected to the internet, log in to the sandbox using the credentials you originally received from Renesas. Those don’t change. In the upper right hand corner of the sandbox, you can now select the project you just created. In this example, the project is DKTemperature, but any name will do.

Once you have selected the new project, the workspace will be empty. All of the tags created by Smart Chef will be available which is fine because you’ll use some of them. Now you can create your first workflow. At this point, the IoT board should be off.

Step 4: Create the Temp Project Initialization Workflow

Create a new workflow and name it “Temp Project Initialization”. Instructions for doing this are in the earlier Home Temperature Monitor tutorial: Home Temperature Monitor with S3A7
or in the Renesas ‘Getting Started Guide’ here:
https://renesas-docs.mediumone.com/

The workflow has a single trigger, ‘raw:connected’ and no output. In the raw stream, there is already a ‘connected’ tag, and you need to make sure it is active. Instructions for doing that are in the Home Temperature Monitor tutorial. The default python code module contains an output node. It does no harm, but it seems clearer to delete it. You can add/delete inputs and outputs by clicking on the arrow next to ‘Inputs/Outputs’ just above the code in a Base Python module.

When the IoT board is powered up and first connects to the sandbox, a raw:connected event is generated. That initiates this whole project.

Here’s the code to place in the Base Python module

'''
This workflow initiates the home temperature and humidity monitor.  
It is triggered when the IoT board with modified 
SmartChef code first comes online.  The trigger is raw:connected.

The workflow creates the global persistent storage value key "temp_data" and initializes it.  This can
be accessed from other workflows.  Read the Renesas IoT Sandbox 'Store Library' documentation
for all of the details.

This workflow also sends a notification via email that temperature monitoring has started.

Created December 15, 2016 by DK

Modified January 17, 2017 by DK

Python.datetime module used to format the time and date in local time
email formatted so it is easier to read

'''

import Email
import Store
import datetime

# Fill in your to/from email addresses here
TO_EMAIL = "email@domain.com"
FROM_EMAIL = "email@domain.com"

# Initialize data storage with key 'temp_data.' 
# By default ttl (time to live) =1 week which is more than enough for this project which records in 24 hour blocks
# ttl can be made infinite if necessary - see library docs.

Store.set_global_data("temp_data", "")

input_dictionary = IONode.get_input('in1')
is_connected = input_dictionary['event_data']['value']
is_connected_str = str(is_connected)

# Note that times are in UTC.  US Pacific Standard is 8 hours behind
# This statement grabs the incoming timestamp in ISO 8601 format
# For this implementation, I decided not to use it since python's datetime is easier
# connected_time_str = input_dictionary['observed_at']

current_datetime_object = datetime.datetime.now() # Grab the local time and create a datetime object
current_timestamp = current_datetime_object.isoformat() 
time_date_list = current_timestamp.split('T') # T separates Date and Time in ISO format
date = time_date_list[0]
rawtime = time_date_list[1]
time_list = rawtime.split('.') # Time format HH:MM:SS.MMMMMMM....Z
time = time_list[0] # Strip off everything after the "."

try:
    email_text = "Connected = "+is_connected_str+"\rConnected at: "+time+"\ron: "+date
    test_email = Email.Email(FROM_EMAIL,'El Guapo',TO_EMAIL,'Temperature Logging Initiated')
    test_email.text_message(email_text)
    test_email.send()
except Exception:
    log("Unable to send Email")

Step 5: Configure the Mobile App

When you open the mobile app on your phone, you’ll be able to add a new profile by clicking on the plus sign. Name the profile something unique and then enter all of the mobile credentials that were emailed to you when you created your new project in step 3 above. In this case, the name is DKTemperature. VERY IMPORTANT: Click on the small arrow in the lower right and select ‘Renesas’ as shown, rather than ‘Sandbox’ or ‘Pro’. Ios is slightly different, but you must select ‘Renesas.’

Once you save the profile, click on the plus sign again and add a ‘Switch’ widget. Once you are done, the screen will look like this.

In Android, swiping the widget to the left displays the following configuration screen. Tapping on the first icon allows you to set the stream to “raw”. The center icon allows you to set the tag to “mobile_temp_request”. Once you have saved everything, swipe right and the switch should look like the final screen below.

Step 6: Create and Activate the raw:mobile_temp_request Tag

At this point, the raw tag ‘mobile_temp_request’ does not yet exist so you can’t create the next workflow which depends on it. By pressing the mobile_temp_request switch you transmit a message containing the raw:mobile_temp_request tag which is auto detected by the sandbox. Note that in this application, the switch is a push button, and its state doesn’t matter. Once you press the switch, return to the sandbox and look under Config:Data Streams:raw.

When you click on ‘Edit’ a list of tags appears and it will now include mobile_temp_request. Check the active box next to it and then save the datastream to activate the new tag.

Step 7: Create the Temperature and Humidity Sampling Workflow

Add a new workflow and name it “Temperature and Humidity Sampling.” This workflow requests temperature and humidity readings from the S3A7 board. There are two request sources. One is a scheduled request, and the other is a mobile request. Add one scheduled trigger and connect it to ‘in1’. This example shows an hourly reading, but you could customize it to suit your needs. Then add a raw:mobile_temp_request trigger and connect it to ‘in2’ which you will need to add to your Base Python module. Here’s the completed workflow.

Finally, here is the code for the Base Python module.

'''
This workflow requests the temperature and humidity from the board.

Last Updated: Sept 15, 2016

Author: Medium One

The mechanics of requesting and reading the temperature and humidity from the S3A7
remain unchanged below.  I added a flag to keep track of what triggered the read - schedule
or a mobile request, since the response of the next workflow will be different.

I also created a new raw stream called temp_and_humidity_mobile for a temp/humidity read
triggered by a mobile request

Updated January 17, 2017 by DK
'''
import MQTT

ENS210_ADDR = 0x43
mqtt_buffer = u''

def write_register(reg, data):
    global mqtt_buffer
    mqtt_buffer += u'3;2;0;3;unused;' + u''.join(map(unichr, [ENS210_ADDR, reg, data]))

def read_register(reg, num, tag_name):
    global mqtt_buffer
    mqtt_buffer += u'3;2;{};2;{};'.format(num, tag_name) + u''.join(map(unichr, [ENS210_ADDR, reg]))
    
# Added by DK to determine what triggered the request
trigger_is_mobile = False
trigger_is_mobile = IONode.is_trigger('in2') #mobile request triggered workflow, not schedule

#read_register(0x00, 2, 'tahcid')
#print mqtt_buffer
#MQTT.publish_event_to_client('s3a7', mqtt_buffer, 'latin1')
#mqtt_buffer = u''
write_register(0x21, 0x03)
MQTT.publish_event_to_client('s3a7', mqtt_buffer, 'latin1')
mqtt_buffer = u''
write_register(0x22, 0x03)
MQTT.publish_event_to_client('s3a7', mqtt_buffer, 'latin1')
mqtt_buffer = u''

if trigger_is_mobile:
    read_register(0x30, 6, 'temp_and_humidity_mobile') #if trigger mobile, use a new raw stream
else:
    read_register(0x30, 6, 'temp_and_humidity') #scheduled -- use standard raw stream
    
MQTT.publish_event_to_client('s3a7', mqtt_buffer, 'latin1')

Step 8: Create and Activate the raw:temp_and_humidity_mobile Tag

The next workflow depends on the raw:temp_and_humidity_mobile tag which doesn’t exist yet. The workflow we just completed generates this tag in code. In order to transmit the tag so that the sandbox will autodetect it, power up the IoT board and make sure it is connected to the internet. Then, press the switch on the mobile app again. After you press the switch, you’ll have to go find the raw:temp_and_humidity_mobile tag and activate it as in step 6.

Step 9: Create the Temperature and Humidity Processing Workflow

Here is the finished workflow.

The raw:temp_and_humidity trigger occurs every time a scheduled temperature and humidity reading happens. In this case, the output goes to another Base Python module which handles logging the data and emailing it as scheduled in code. The raw:temp_and_humidity_mobile trigger occurs every time a mobile user presses the mobile_temp_request button. In that case the output is a processed stream which represents the temperature in degrees Fahrenheit. That processed stream then triggers our final workflow (next step) which pushes the temperature to the mobile device

Begin with the central Base Python module. Once you have dragged it onto the workspace, add a second input (in2) and a second output (out2). Create the two triggers that we need, then connect the raw:temp_and_humidity trigger to in1, and connect the raw:temp_and_humidity_mobile trigger to in2. Drag a second Base Python module on to the workspace and connect it as shown to out1. Finally, connect a single processed stream to out2.

Here is the code for the primary Base Python module that contains two inputs and two outputs.

'''
This workflow decodes the temperature and humidity from the sensor.

Last Updated: Sept 15, 2016

Author: Medium One
'''

'''
This code was all copied verbatim from the SmartChef workflow for reading/decoding
the temperature and humidity from the ENS201 sensor.  My only modification
was to change the output so it is reported in degrees Fahrenheit.

Updated December 15, 2016 by DK
'''

'''
To accommodate mobile temperature requests, I added a flag to keep track of
which input triggered the workflow.  If the trigger was scheduled, the output stream
out1 uses the tag 'temperature'.  Otherwise the output stream out2 uses 'temperature_mobile'.

Updated January 19, 2017 by DK
'''

CRC7WIDTH = 7
CRC7POLY = 0x89
CRC7IVEC = 0x7F
DATA7WIDTH = 17
DATA7MASK = ((1<<DATA7WIDTH)-1)
DATA7MSB = (1<<(DATA7WIDTH-1))

trigger_is_mobile = False
trigger_is_mobile = IONode.is_trigger('in2') #mobile request triggered workflow, not schedule

# The crc7(val) function returns the CRC-7 of a 17 bits value val.
# Compute the CRC-7 of 'val' (should only have 17 bits)
def crc7(val):
    # Setup polynomial
    pol = CRC7POLY
    # Align polynomial with data
    pol = pol << (DATA7WIDTH-CRC7WIDTH-1)
    # Loop variable (indicates which bit to test, start with highest)
    bit = DATA7MSB;
    # Make room for CRC value
    val = val << CRC7WIDTH
    bit = bit << CRC7WIDTH
    pol = pol << CRC7WIDTH
    # Insert initial vector
    val |= CRC7IVEC
    # Apply division until all bits done
    while( bit & (DATA7MASK<<CRC7WIDTH) ):
        if( bit & val ):
            val ^= pol
        bit >>= 1
        pol >>= 1
    return val

if trigger_is_mobile: #input came from in2 as a result of mobile request
    handt = IONode.get_input('in2')['event_data']['value']
else: #input came from in1 and is standard scheduled request
    handt = IONode.get_input('in1')['event_data']['value']
    

out_temp_hum = {}
out_mobile = {}

t_val = handt[0] | (handt[1] << 8) | (handt[2] << 16)
h_val = handt[3] | (handt[4] << 8) | (handt[5] << 16)
t_data = t_val & 0xffff;
t_valid = (t_val >> 16) & 0x1;
t_crc = (t_val >> 17) & 0x7f;
h_data = h_val & 0xffff;
h_valid = (h_val >> 16) & 0x1;
h_crc = (h_val >> 17) & 0x7f;
print "t_data: {}, t_valid: {}, t_crc: {}, h_data: {}, h_valid: {}, h_crc: {}".format(t_data, t_valid, t_crc, h_data, h_valid, h_crc)
if t_valid:
    t_payl = t_val & 0x1ffff;
    calc_t_crc = crc7(t_payl)
    if calc_t_crc == t_crc:
#       out['temperature'] = round(float(t_data) / 64 - 273.15,2)
# I commented out the above line and added the four lines below to output in Fahrenheit
        TinK = float(t_data) / 64 
        TinC = TinK - 273.15
        TinF = round(TinC * 1.8 + 32,2)
        if trigger_is_mobile:
            out_mobile['temperature_mobile'] = TinF
        else:
            out_temp_hum['temperature'] = TinF
    else:
        log("Invalid temperature CRC, expected: {}, actual: {}".format(calc_t_crc, t_crc))
if h_valid: 
    if trigger_is_mobile != True: # Only calculate humidity if scheduled event
        h_payl = h_val & 0x1ffff;
        calc_h_crc = crc7(h_payl)
        if calc_h_crc == h_crc:
            HinPercent = round(float(h_data) / 512,2)
            out_temp_hum['humidity'] = HinPercent
        else:
            log("Invalid humidity CRC, expected: {}, actual: {}".format(calc_h_crc, h_crc))

if trigger_is_mobile: # Mobile temperature request
    IONode.set_output('out2', out_mobile)
else: # Scheduled temp and humidity request
    IONode.set_output('out1', out_temp_hum)

Here is the code for the Base Python module which is triggered by ‘out1’ from the previous module.

'''
This workflow takes processed temperature and humidity data and stores it in a 
persistent global location using the Renesas Store class library.
Data is logged at an interval set by the workflow trigger definition 
(one hour in this case) and emailed after a certain
number of datapoints are recorded.  The data file is wiped clean after
the file is emailed.

Created on: December 15, 2016 by DK

'''

import Email
import Store
import datetime

# Enter the email addresses you'd like to use
FROM_EMAIL = "addressk@domain.com"
TO_EMAIL = "address@domain.com"

# Number of data readings before the log is emailed and erased
NUM_READINGS = 24

# The call to global key "temp_data" returns saved data_log in unicode
data_log = Store.get_global("temp_data")

# Convert to a str object ... now the file is a long string that can be appended
# The instructions for doing this are in the 'Store Library' documentation on the Medium One website
data_log_str = "" # Initialize the string variable which will hold file contents
data_log_str = data_log.encode("latin-1")

input_dictionary = IONode.get_input('in1')
temp_in_f = input_dictionary['event_data']['temperature']
temp_in_f_str = str(temp_in_f)

humidity_in_percent = input_dictionary['event_data']['humidity']
humidity_str = str(humidity_in_percent)

current_datetime_object = datetime.datetime.now() # Grab the local time and create a datetime object
current_timestamp = current_datetime_object.isoformat() 
time_date_list = current_timestamp.split('T') # T separates Date and Time in ISO format
date = time_date_list[0]
rawtime = time_date_list[1]
time_list = rawtime.split('.') # Time format HH:MM:SS.MMMMMMM....Z
time = time_list[0] # Strip off everything after the "."

# Note that time is in UTC.  Pacific Standard Time is 8 hours behind UTC
reading = "Date: "+date+" Time: "+time+"  Temperature: "+temp_in_f_str+"  Humidity: "+humidity_str+"\r"

# Now, append the global file string with the new reading
data_log_str = data_log_str+reading

# Count the number of readings in the string by counting "\r" return characters
number_of_readings = data_log_str.count("\r")

if number_of_readings < NUM_READINGS:    #Less than required number of readings
    Store.set_global_data("temp_data", data_log_str)    #Save the appended file
else:  #Number of readings = NUM_READINGS.  Time to email and reset
    try:
        test_email = Email.Email(FROM_EMAIL,'El Guapo',TO_EMAIL,'Temperature Data Log')
        test_email.text_message(data_log_str)
        test_email.send()  
        Store.set_global_data("temp_data", "") # Clear the data so the process can start over
    except Exception:
        log("Unable to send Email")
        Store.set_global_data("temp_data", "") # Clear the data so the process can start over

Step 10: Create and Activate the processed:temperature_mobile Tag

Now you need to create and activate one final tag in order to build the final workflow. Again, this tag is generated by the code in the workflow we just finished. In order to generate the tag, you press the mobile_temp_request switch one more time with the IoT board connected. Once you’ve pressed the mobile switch, find the temperature_mobile tag which is in the processed stream this time. After you activate and save it, you can create the final workflow.

Step 11: Create the Push Notification Temp to Mobile Workflow

The final workflow is triggered whenever a processed:temperature_mobile event occurs in response to a pressed mobile app switch. It is also triggered by a raw:FCM_token event which occurs when the mobile app connects to the project. If the trigger is a temperature_mobile request, the cloud will push the temperature measurement to the mobile device. If the trigger is a raw:FCM_token, the cloud just pushes a ‘connected’ message to the mobile device. Here’s the complete workflow.

Finally, here is the code for the Base Python module.

'''
This workflow handles temperature mobile push notifications.  When the mobile app is connected
and an FCM token is shared, a push notification is sent to the mobile app.  Also, whenever
the mobile app requests the temperature, a push notification is sent with the current
temperature.  Push notifications include time, so I didn't bother to include time or date
in the notification.

Created: January 20, 2017 by DK
'''

import FCM

input_dictionary = IONode.get_input('in1')
temperature = input_dictionary['event_data']['value']
temp_string = str(temperature)
FCM_token = IONode.get_input('in2')['event_data']['value']
trig_is_FCM = IONode.is_trigger('in2') 
if trig_is_FCM: #workflow triggered by raw:FCM_token rather than temperature_mobile
    FCM.send_fcm_notification_to_m1_application([FCM_token],"Mobile temp monitor initiated",sound='chime')
else: #workflow triggered by temperature_mobile
    FCM.send_fcm_notification_to_m1_application([FCM_token],"temperature: "+temp_string+" F",sound='chime')

When all of this is done, and the four workflows are activated, reset or cycle power on the IoT board to initiate logging. Once the board connects, you’ll receive an email like this one.

As long as the board remains powered on, you’ll receive data log emails with the number of readings you specify in code at the interval you specify in the scheduled trigger for the Temperature and Humidity Sampling workflow. Here’s an example where the number of readings is 5 and the schedule interval is one minute.

Note that the time interval isn’t exactly one minute. That is because rather than parsing the actual timestamps, the workflow uses the python datetime library.

At any time, you can also use the mobile app to request a temperature reading by pressing the mobile_temp_request switch that you created in step 5. After pressing the switch there will be a short delay until you receive a push notification from the sandbox which looks like this on Android.

At first, I hoped to display the requested temperature data on a gauge widget. Unfortunately, that is a ‘real time’ widget, and because it polls the cloud every two seconds, it will chew through your workflow credits very quickly. Medium One recommends push notifications, and they are the best for this application.

Next Steps:

This seems like a useful model for monitoring many different environmental quantities. I’m going to try to repeat this with a pH sensor. I happen to bake sourdough bread. The dough ferments for anywhere from 6 to 48 hours depending on the temperature. During that time, bacteria produce lactic acid and acetic acid which slowly lower the pH of the dough and make it more sour. Because the temperature varies, the time until the dough is ready varies. It would be very useful to log the pH over time and send a push notification when the pH hits a particular level indicating that it is ready. pH monitoring would also be useful for swimming pools, hot tubs, and even environmental water quality in lakes/streams.


Learn IoT MeetUp - Apr 19 in San Jose
SK-S3A7 Tutorials
Learn IoT MeetUp and Workshop - Jan 23 in Santa Clara
#2

Dan, super cool, I’m still reading through it, but this seems like a really good progression from the first Home Temperature Monitor with S3A7 tutorial you wrote before. I like Steps 5 and 6 for setting up mobile_temp_request tab. Great to get a reading when you request it through your phone. Very slick! :slight_smile:


#3

Thanks, Jesse. Let me know if you find anything that is unclear. The system worked very well for me. I like this second iteration much better than the first, although the original home temperature monitor is a good way to get your feet wet with the technology.


#4

There’s a great new video here on the Medium One mobile app.