Salesforce NodeMCU IoT Temperature Service
Author : Dinesh Kumar Wickramasinghe
Introduction
Hello friends, this project is about sending real time sensor data to the world’s number 1 CRM platform, Salesforce. In profession, I am a Salesforce developer and I did a simple experiment of sending real time temperature data that coming from DS18B20 digital temperature sensor to Salesforce using NodeMCU IoT Platform. I implemented a public REST API on my Salesforce developer org and the NoceMCU consumes this web service to send real time data. So this tutorial will explain all the steps I’ve followed to accomplish this project.
What is Salesforce?
If you are new to Salesforce CRM, this information is for you. Salesforce is the world's number one CRM (Customer Relationship Management) company. Salesforce provides a cloud based platform to develop business applications to improve customer relations. It has their own programming language called APEX for advanced business application development and a database query language called SOQL for querying. The platform also has a front end framework called Visualforce to create dynamic web pages. Salesforce also provides several declarative (Point and click) features to build business application faster even without writing single line of code. Salesforce recently introduced their stunning front end framework called Lightning to build mobile enabled and responsive applications with rich UI Components.
If you are willing to learn more about salesforce, please reach their interactive learning platform called Salesforce Trailhead.
To start investigating more about Salesforce and to complete this tutorial, you can create a free developer account by following the below link :
Sign up for new Salesforce account
High Level Architecture
Below diagram shows the high level data flow of our project.
Salesforce Configurations
Now I will step by step explain you what are the configurations we need to do on Salesforce.
1. Custom object to Store Data
Salesforce custom object is like a Database table. So we are going to create a custom object to save temperature data coming from the web service.
Custom object name : Temperature Data (API Name : Temperature_Data__c)
Also create below custom fields on your Custom object.
Field Name
|
Data Type
|
Comments
|
Celsius__c
|
Number(10, 2)
|
Temperature data in celsius format
|
Fahrenheit__c
|
Formula (Number)
|
Celsius__c * 9.0 / 5.0 + 32.0
|
Is_Critical__c
|
Checkbox
|
Indicates whether the temperature value is critical or not
|
Please see the below screenshot of my custom object for more details. Also create a custom tab for this custom object. Then we can easily monitor the values of this object.
1. Apex Trigger
In this step, we are going to write a simple Apex trigger for the above custom object. This trigger will execute after you insert a new temperature record. If you carefully go through this simple trigger code, you can see that, if the temperature value (Celsius value) is above 50, then it creates a new Case record.
Also it calls a simple email sending method to send an email alert (Please replace the 'youremail@youremail.com' with your email address). Please note that you can modify this code in many ways. I wrote just a simple code to understand easily.
trigger TemperatureAlertTrigger on Temperature_Data__c(after insert) {
//Get the Trigger's new data list
Temperature_Data__c[] newTempDataList = Trigger.new;
//Get the first data point
Temperature_Data__c temperatureDataPoint = newTempDataList[0];
//Get the temperature value
Double celsiusValue = temperatureDataPoint.Celsius__c;
//Check if the temperature is above the critical value
if (celsiusValue > 50) {
//Create a new case and set required data
Case crtTemCase = new Case();
crtTemCase.Status = 'New';
crtTemCase.Origin = 'Device';
crtTemCase.Subject = 'Temperature Alert from Device';
crtTemCase.Description = 'The device temperature is increasing above the critical point. \n\n Temperature : ' + celsiusValue;
crtTemCase.Reason = 'Other';
crtTemCase.Type = 'Mechanical';
crtTemCase.Priority = 'High';
//Insert the case
insert crtTemCase;
//Send alert mail
try {
sendMail(celsiusValue);
} catch (Exception ex) {
System.debug('MAIL ERR ' + ex);
}
}
/*
* This method will send email alerts when the temperature is
* above the critical point
*/
public void sendMail(Double temperature) {
Messaging.reserveSingleEmailCapacity(2);
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {
'youremail@youremail.com'
};
mail.setToAddresses(toAddresses);
mail.setSenderDisplayName('Critical Temperature Alert');
mail.setSubject('Temperature Alert');
//mail.setPlainTextBody('Temperature : ' + temperature);
mail.setHtmlBody('Temperature: ' + temperature + ' C
' + 'Please take the necessary actions.
');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {
mail
});
}
}
Please proceed the below link to learn more about Apex triggers.
Salesforce Apex Triggers
1. REST Web Service
In this step, we are going to write a simple salesforce REST web service and expose this as a publically accessible service. So, later we can invoke this web service using NodeMCU and send temperature data.
Create a new Apex class and paste the below code.
@RestResource(urlMapping = '/iotservice')
global class RealTimeDataService {
@HttpGet
global static void doGet() {
//Set the response as plaintext
RestContext.response.addHeader('Content-Type', 'text/plain');
//Get the temperature value from the parameter
String tempReading = RestContext.request.params.get('temperature');
//Convert the string value to Double
Double tempDoubleReading = Double.valueOf(tempReading);
//Create a new custob object record to store the value
Temperature_Data__c temperatureRecord = new Temperature_Data__c();
temperatureRecord.Celsius__c = tempDoubleReading;
//Set the critical checkbox to true
if (tempDoubleReading > 50) {
temperatureRecord.Is_Critical__c = true;
}
try {
//Insert the temperature value, if success, send success response
insert temperatureRecord;
RestContext.response.responseBody = Blob.valueOf('sucess');
} catch (Exception ex) {
//If the insertion fails, send error response
RestContext.response.responseBody = Blob.valueOf('error');
}
}
}
We use the HTTP GET method to receive data. You can see that this trigger receives the celsius value as a parameter and creates a new record of the type of custom object we created in an earlier step (Temperature_Data__c).
If the celsius value is greater than 50, the logic set the Is_Critical__c field of our custom object to true. Please note that the Fahrenheit value will be automatically calculated since it is a formula field.
We need one last step to do on Salesforce before we move to NodeMCU configurations.
1. Make the REST service public
The web service we created in the previous step is not publicly accessible. So we are going to create a Salesforce site and expose this REST service via this public site. So that the NodeMCU can easily invoke this service without worrying about authentication.
Go to "Sites" on Salesforce setup and create a new site. Use the site name "TemperatureService"
Go to "Public Access Settings" of the site and click on "Enabled Apex Class Access"
Click the Edit button.
Move the web service class "RealTimeDataService" from the "Available Apex Classes" group to "Enabled Apex Classes" group.
Save your configurations.
Now we’ve done with all our configurations on Salesforce side. Now let’s move to our hardware setup. See the below blog post for more details about public RESTful web services.
Quick Tip – Public RESTful Web Services on Force.com Sites
Follow this link to learn more about Salesforce sites :
More about Salesforce sites
Configuring Node MCU
As I mentioned in the beginning of this tutorial, we use the NodeMCU IoT platform to send real time sensor data to Salesforce.
I’ve written two blog posts about NodeMCU. I recommend you to go through them before continue. They will give you an introduction knowledge about NodeMCU device and Configuring the Arduino IDE for NodeMCU programming.
- Introduction to Node MCU
- LED Blink with Node MCU
Schematic (Circuit Diagram)
Please use the below circuit diagram to setup your devices. You need below things to setup your devices.
- ESP8266 Based NodeMCU IoT Platform
- A Solderless development board
- Some hook up wires
- DS18B20 Digital temperature sensor
- 4.7K Resistor
Setting Up Arduino IDE
If you referred my introduction tutorials for NodeMCU, you can learn how to setup the Arduino IDE for NodeMCU and how to upload a simple code. So, I am not going to explain those steps again here.
In this demo, we need to install two additional libraries to Arduino IDE. Those libraries will help us to read the DS18B20 Digital Temperature Sensor.
- One Wire
- Dallas Temperature
Go to Arduino IDE Menu : Sketch > Include Library > Manage Libraries
On Library manager window, first search for "onewire" and install the onewire library as on below screenshot.
Then search for "dallas" and install the dallasTemperature library as on below screenshot.
OK, Now your Arduino IDE is ready to write and upload the software for NodeMCU.
NodeMCU Code
Here is the source code for NodeMCU.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define USE_SERIAL Serial
#define ONE_WIRE_BUS 2
ESP8266WiFiMulti WiFiMulti;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
char temperatureString[6];
void setup() {
USE_SERIAL.begin(115200);
//USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("MORPHEUS", "rvd@#ell12");
DS18B20.begin();
}
float getTemperature() {
float temp;
do {
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0);
delay(100);
} while (temp == 85.0 || temp == (-127.0));
return temp;
}
void loop() {
float temperature = getTemperature();
dtostrf(temperature, 2, 2, temperatureString);
USE_SERIAL.println("Reading");
USE_SERIAL.println(temperatureString);
if((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n");
// configure traged server and url
http.begin("https://iotservice-developer-edition.ap5.force.com/sensordata/services/apexrest/iotservice?temperature=" + String(temperatureString), "B0 9B F8 CD F9 7A FD DD 0F 86 3B E3 87 FA 7F FE 88 4C 61 02");
//http.begin("http://192.168.1.12/test.html"); //HTTP
USE_SERIAL.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if(httpCode > 0) {
// HTTP header has been send and Server response header has been handled
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
USE_SERIAL.println(payload);
}
} else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
delay(5000);
}
There are few places you need to change on the above code.
Add your WiFi network SSID and password here.
WiFiMulti.addAP("AndroidHotspot4984", "dinesh1234");
You also need to change the below line with your Salesforce org details (Service URL and SHA1 Fingerprint). Let's see how.
http.begin("https://iotservice-developer-edition.ap5.force.com/sensordata/services/apexrest/iotservice?temperature=" + String(temperatureString), "B0 9B F8 CD F9 7A FD DD 0F 86 3B E3 87 FA 7F FE 88 4C 61 02");
REST API URL format.
You need to replace the API URL with your web service URL. Now let’s see how to populate the correct URL. For an example, here is my web service URL.
https://iotservice-developer-edition.ap5.force.com/sensordata/services/apexrest/iotservice?temperature=
Now let’s see how this URL is populated. Here are the components of this URL you need to change according to your Salesforce organization.
https://iotservice-developer-edition.ap5.force.com : Domain name of your custom URL
/sensordata : Path
/services/apexrest : This part is common for REST service
/Iotservice : URL Mapping you’ve given in your REST web service class
temperature : Parameter name you’ve given in your web service class
So, based on your Salesforce organization settings, build the correct URL. You can test this URL by sending a sample temperature value via the web browser. Make sure to add a temperature value at the end of this URL. See the below screenshot.
If the service call was success, you will see a success response. When you get the success response, you can check from Salesforce backend if the record is correctly inserted to the custom object using a SOQL query or using a custom tab for your custom object.
Getting the SHA1 Fingerprint
Since we are accessing a HTTPS URL via NoceMCU, we need to get the SHA1 fingerprint of your salesforce url. Here is a simple hack to get it.
Node : I am not sure that this is the best way to get the SHA1 Fingerprint. If you know a better way than this, please comment ;)
Go to the service URL (you populated above) using Mozilla Firefox Browser
Click on the green color pad lock Icon.
Then click on 'Show Connection Details' button.
Then click on more information.
On the Page Info window, Click view certificate
Bottom of the certificate viewer window, you will see your SHA1 Fingerprint as below.
Copy it and replace all the colon signs with spaces. Now it should look like this
B0 9B F8 CD F9 7A FD DD 0F 86 3B E3 87 FA 7F FE 88 4C 61 02
In the nodeMCU code, replace my fingerprint with your one. Now you've done all the changes to your NodeMCU code.
Once you done all the necessary changes on the code, plug your NodeMCU module to your PC and upload the code.
Running the Project
If everything went well, it is time to launch the project. You can power up the NodeMCU via your PC or Laptop USB port or by using an external power supply. I recommend you to power up via the USB port since it is safe.
Make sure your WiFi network is up and running and your internet connection is active on WiFi. Because once we power up the device setup, NodeMCU will connect to your WiFi network and after that it will start reading the temperature and finally invoke the web service URL.
The device setup will invoke the web service every 10 seconds and send a temperature value to Salesforce.
You can open the serial monitor of your Arduino IDE and see what is happening in the back end. Click on the below icon of your arduino IDE to open the serial monitor window.
If everything going well, you will see an output similar to below screenshot.
Login to your Salesforce org (if you are not already logged in) and open the custom tab you created for the custom object. Time to time refresh the data and you will see new data coming from the sensor.
If the temperature is increased above 50 celsius degrees, a case will be opened and an email alert will be sent. To test this, you can increase the temperature of the sensor by putting it inside a hot water glass ;) (No worries, it is a waterproof sensor)
If you open the Cases tab, you will see cases open if the temperature is increased above 50 celsius degrees. I have one case as below.
Click on the case name to see the case details.
You can also check your email account to see the critical temperature alert mail.
Here is a video clip I took while doing this project.
Conclusion
So, this is the end of this tutorial. Hope you enjoyed it. Please note that if you are new to Salesforce, you will have some questions while doing this project. So, please refer the links I’ve given you in the beginning of this tutorial to update your Salesforce knowledge.
Salesforce recently introduced a new cloud (service) calls Salesforce IoT Cloud. This has more features specially for IoT projects. I will post a new article soon related to the IoT cloud.
If you have any questions, suggestions or if you found any mistakes made by me while writing this blog post, please mention them as a comment. I will response my best. Thank you!