Using a SHTC3 Temperature Sensor With Wemos D1 Mini

by pp3dp_se in Circuits > Arduino

896 Views, 0 Favorites, 0 Comments

Using a SHTC3 Temperature Sensor With Wemos D1 Mini

20221213_081806.jpg
20221213_081836.jpg
20221213_081844.jpg

I needed to use SHTC3, instead of the more common DS18B20 with my Wemos D1 mini boards

There is not much information on the net regarding this, so why not share what I discovered

The code provided starts a unique sensor node with AP and a simple webserver that let's you connect to your own wifi:

Set SSID and password

http://192.168.4.254/wifi?ssid=YOURSSID&pwd=YOURPASSWORD

Reboot

http://192.168.4.254/reboot


It publishes data and sensor id to a webserver, Node Red in my case


You need to create fingerprint for https access, or use certificate as described in links


Deepsleep is implemented (It needs the response "DEEPSLEEP" from webserver to activate), proper setup between RST/D0 is needed though

It also uses Taskmanager, for a more RTOS feel

The code contains links to more information

Github Gist


Supplies

Prepare Enviroment

  1. Start by installing the latest version of Visual Studio Code and the PlatformIO IDE extension.
  2. Open Visual Studio Code and click on the PlatformIO icon in the sidebar to open the PlatformIO dashboard.
  3. Click on the "Projects" tab and then click on the "New" button to create a new project.
  4. Select the "Wemos D1 mini" board and the "esp8266" framework, and give your project a name.
  5. In the PlatformIO dashboard, click on the "Platforms" tab and search for the "Adafruit SHTC3" library.
  6. Click on the "Install" button next to the SHTC3 library to add it to your project.
  7. Repeat this for "Wire", "SPI" and "Taskmanager (davetcc)"

Verify your platform.ini and also change monitor_speed to catch esp8266 boot messages:

[env:wemos_d1_mini32]
platform = espressif8266
board = d1_mini_lite
framework = arduino
upload_speed = 115000
monitor_speed = 76800
lib_deps =
    davetcc/TaskManagerIO@^1.3.0
    Wire
    SPI
    adafruit/Adafruit SHTC3 Library@^1.0.1


Prepare Hardware

esp8266-wemos-d1-mini-pinout.png
  1. Connect the SHTC3 sensor,
  2. SCL>D1
  3. SDA>D2
  4. 5v and GND

Modify Adafruit Library!

Locate Adafruit_SHTC3.cpp, it's under .pio\libdeps\wemos_d1_mini32\Adafruit SHTC3 Library

Search for "bool Adafruit_SHTC3::begin"

Change the code that match below, you need the value that prints out

You could also remove the if statement completely

// read the ID
  //was != 0x807 but that is not the ID of the SHTC3
  if ((readID() & 0x083F) != 48 /* This is the value that need to be changed */) {
    Serial.println(readID() & 0x083F); //Patrick
    return false;
  }

Replace Main.cpp

  1. Change main.cpp with below code our from the gist
  2. Change to your own domain for sensor data
  3. Create fingerprint for https or import certificates as described in links
  4. Upload and test
  5. Enjoy
#include <Arduino.h>
#include "TaskManagerIO.h"
#include <ESP8266WiFi.h>
#include <MQTT.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include <EEPROM.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <Wire.h>

/*

IMPORTANT!
If you are using a Wemos D1 Mini, you need to connect the D0 pin to the RST pin with a 150 ohm resistor.
This is because the D0 pin is used for deep sleep, and the RST pin is used for uploading new sketches.

IMPORTANT!
This code uses Adafruit_SHTC3 library, which is a modified version of the Adafruit_SHT31 library.
The modifications are to make it work with the Chinese SHTC3 sensor.

Turn on debug in Adafruit_I2CDevice.cpp

#define DEBUG_SERIAL Serial

In Adafruit_SHTC3::begin, Adafruit_SHTC3.cpp

Change the id in this part, to the value that it outputs

// read the ID
//was != 0x807 but that is not the ID of the SHTC3
if ((readID() & 0x083F) != 48) {
Serial.println(readID() & 0x083F); //Patrick
return false;
}

HTTPS FINGERPRINT, not implemented fully, hard coded for now
https://maakbaas.com/esp8266-iot-framework/logs/https-requests/
https://github.com/maakbaas/esp8266-iot-framework/blob/master/docs/fetch.md

I2C Scanner
http://www.esp8266learning.com/i2c-scanner.php


Wemos D1 Mini Pinout
https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/


Wemos D1 Mini Deep sleep
https://kevinstadler.github.io/notes/wemos-d1-mini-clones-sleep-mode-current-power-consumption-esp8266/

Wemos Deep sleep garbage via serial
https://arduino.stackexchange.com/questions/58194/d1-mini-does-not-resume-operation-as-expected-after-deep-sleep

Do not forget rst/d0

"After performing some tests on the resistor between D0 and RST, I have found that 150 ohm allows new sketches to be uploaded, and also enables RST from D0 so that deepsleep executes properly.

With 1 kohm the deepsleep do not properly start, and with a wire between D0 and RST I was not able to upload new sketches without disconnecting the wire.

With 150 ohm, both functions seems to function as they should."

PlatformIO monitor baudrate
https://community.platformio.org/t/serial-monitor-baudrate/5837

*/
#include "Adafruit_SHTC3.h"

#define DEBUG_SERIAL
Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();

//Https FINGERPRINT FOR YOUR DOMAIN, need to be changed!!!
//IMPORTANT! This is not implemented fully, hard coded for now

const uint8_t fingerprint[20] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0x8e, 0xa3, 0xad, 0xfa, 0x1a, 0xe8, 0x25, 0x41, 0x1d, 0x1a, 0x54, 0xb3};

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

int counter=0;

//Wifi credentials
char ssid[] = "YOURSSID";
char pass[] = "YOURPASSWORD";


//Wifi AP credentials
const char ssidAP[] = "WD1_AP";
const char passAP[] = "1234567890";

//WIFI slot for eeeprom
struct {
uint val = 0;
char ssid[64] = "";
char pass[64] = "";
} data;

ESP8266WebServer server(80);

WiFiClient net;
MQTTClient client;

//Connects to wifi, also waits for changing wifi credentials, while in AP mode
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
server.handleClient();
Serial.print(".");
delay(1000);
}
Serial.println("Connected");
}

//Handles wifi arguments from the webserver
//Allows you to change the wifi credentials
void handleWifiArgs() { //Handler

String message = "Number of args received:";
message += server.args(); //Get number of parameters
message += "\n"; //Add a new line
String ss = "";
String pwd ="";
for (int i = 0; i < server.args(); i++) {

message += "Arg n" + (String)i + " –> "; //Include the current iteration value
message += server.argName(i) + ": "; //Get the name of the parameter
message += server.arg(i) + "\n"; //Get the value of the parameter

if(server.argName(i) == "ssid")
{

ss = server.arg(i);
}

if(server.argName(i) == "pwd")
{

pwd = server.arg(i);
}

}
if (ss !="" && pwd !="")
{
Serial.print("EEPROM updated\n");
uint addr = 0;
EEPROM.begin(512);
ss.toCharArray(data.ssid,64,0);
pwd.toCharArray(data.pass,64,0);
EEPROM.put(addr,data);
EEPROM.commit();
}

server.send(200, "text/plain", message); //Response to the HTTP request

}

//Handles reboot arguments from the webserver
void handleRebootArgs(){

ESP.restart();
}

//
// A simple logging function that logs the time and the log line.
//
void logIt(const char* toLog) {
Serial.print(millis());
Serial.print(':');
Serial.println(toLog);
}

//
// here we globally store the task ID of our repeating task, we need this to cancel it later.
//
int taskId;

//
// A task can either be a function that takes no parameters and returns void, a class that extends Executable or
// if you want to call with parameters either ExecWithParameter or ExecWith2Parameters
//
void twentySecondJob() {
logIt("20 seconds one off task");
logIt("stop 1 second task");
//taskManager.cancelTask(taskId);
taskManager.scheduleOnce(10, [] {
logIt("Ten more seconds done finished.");
}, TIME_SECONDS);
}

//Sends sensor data to the webserver, with unique ID
void Publish2NodeRed(){

sensors_event_t humidity, temp;

shtc3.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data

HTTPClient http;
Serial.println("Dumping data to NodeRed");

char outputString[10];
//GET UNIQUE ID
itoa(system_get_chip_id(), outputString, 16);

String nodered = "https://YOURDOMAIN/?data=" + String(temp.temperature) + "&id=" + String(outputString);
Serial.println(nodered);

WiFiClientSecure client;
client.setInsecure();
http.begin(client,nodered);
http.addHeader("Content-Type", "text/plain"); //Specify content-type header

int httpCode = http.GET(); //Send the request
String payload = http.getString();
Serial.println(payload);

counter++;
//Should we deepsleep?
if (payload=="DEEPSLEEP")
{
Serial.println("Enter deepsleep");
ESP.deepSleep((5*60) * 1000000,WAKE_RF_DEFAULT) ;
}
}

//Scans for I2C devices
void ScanI2C()
{
byte error, address;
int nDevices;

Serial.println("Scanning...");

nDevices = 0;
for(address = 1; address < 127; address++ )
{

Wire.beginTransmission(address);
error = Wire.endTransmission();

if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");

nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");

delay(5000); // wait 5 seconds for next scan
}


//Reads from the SHTC3 sensor
void ReadSHTC3() {
sensors_event_t humidity, temp;

shtc3.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data

Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");

delay(1000);
}

/*
Initilization of I2C and SHTC3
Scans for I2C devices and prints out shtc3 sensor id
Loads the EEPROM data, containing the SSID and password
Starts AP wifi
Starts webserver
Starts taskmanager

*/
void setup() {
Wire.begin();
//Serial.begin(9600);
Serial.begin(76800); // for ESP boot loader debug
ScanI2C();
//find shtc3
Serial.println("SHTC3 test");
if (! shtc3.begin()) {
Serial.println("Couldn't find SHTC3");
while (1) delay(1);
}
Serial.println("Found SHTC3 sensor");

ReadSHTC3();





//Load EEPROM data and initialize if not set
uint addr = 0;
EEPROM.begin(512);
EEPROM.get(addr,data);

if(data.val==0)
{
Serial.println("Old values are: "+String(data.val)+","+String(data.ssid)+", " + String(data.pass));
data.val +=1;
strncpy(data.ssid, "NOSSID",64);
EEPROM.put(addr,data);
EEPROM.commit();
}
else
{
Serial.println("Old values are: "+String(data.val)+","+String(data.ssid)+", " + String(data.pass));

}

//Start AP
Serial.println("Wemos D1 Starting AP");

IPAddress local_IP(192,168,4,254);
IPAddress gateway(192,168,4,9);
IPAddress subnet(255,255,255,0);
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(local_IP, gateway, subnet);

char outputString[10];

itoa(system_get_chip_id(), outputString, 16);
char outp[strlen(ssidAP)+strlen(outputString)];
strcpy(outp,ssidAP);
strcpy(outp+strlen(ssidAP),outputString);
Serial.println(outp);
WiFi.softAP(outp, passAP); //begin WiFi access point

Serial.print(WiFi.softAPIP());

//Start webserver and args
server.on("/wifi", handleWifiArgs); //Associate the handler function to the path
server.on("/reboot", handleRebootArgs); //Associate the handler function to the path
server.begin();

WiFi.begin(data.ssid, data.pass);

// Wait for connection to wifi
connect();

//Start our sensor task, 15 minute interval
taskManager.scheduleFixedRate(60*15,Publish2NodeRed,TIME_SECONDS);

//Taskmanager examples
/*
// schedule a task to run at a fixed rate, every 1000 milliseconds.
taskId = taskManager.scheduleFixedRate(5000, [] {
logIt("Fixed rate, every 5 second");
});

// schedule a task to run once in 20 seconds.
taskManager.scheduleOnce(20, twentySecondJob, TIME_SECONDS);

// schedule a task to be executed immediately as a taskManager task.
taskManager.execute([] {
logIt("To do as soon as possible");
});
*/
}

//
// All programs using TaskManager need to call taskManager.runLoop in the loop
// method, and should never use delay(..)
//
void loop() {
// Optional:
// If you wanted to go into a low power mode between tasks, you can use taskManager.microsToNextTask() to determine
// how long you can sleep before the next execution. If you use interrupts, ensure the low power mode supports them.
//auto delay = taskManager.microsToNextTask();
//yourLowPowerMode.sleep(delay);
HTTPClient http;

server.handleClient();

taskManager.runLoop();
}