Send two different kinds of sensor data using Arduino - c++

I'm trying to config an Arduino with a PIR motion detector, to send motion detector data and some randomly generated temperature to the gateway.
I want to make it send "MO/1" once motion is detected and still keep sending temperature every 20 seconds like "T/26".
I've used this code but no success:
void loop() {
if (motion == HIGH) {
// Motion Detected
// Send to Gateway
}
while (1) {
temp = random(1,5) + 28;
// Send to Gateway
delay(20000);
}
}
As you may notice, once Arduino enters while it won't pay attention to the if block! Since I'm new to Arduino and programming them, I thought someone could help with this.

This won't work as you noticed.
You need to use a variable, to calculate the time elapsed since last check.
unsigned long t1;
void setup() {
...
t1=millis();
}
void loop() {
if (motion == HIGH) {
// Motion Detected
// Send to Gateway
}
if(millis()-t1>20000) {
temp = random(1, 5) + 28;
// Send to Gateway
t1=millis();
}
}

Related

Using ESP_NOW with loop and delays

I'm trying to receive a data from one esp32 to another.
I'm also doing some looping with delays for reading a sensor data and switch on/off relay cooling.
This device also use ESPAsyncWebServer as API server (not included in code for the size).
I'm receiving the data from one eps32 in POST request to API right now. I would like to change this as to be able to recieve with esp_now. I was doing some experiments, but the data receving is delayed because of delay method in loop.
Is there a way to make this asynchronized as for example the ESPA above?
I also tried a way with comparing a milis() (time) to wait for a loop, but I thing that is too "resource consuming" task, to let it compare in full speed in loop like a vortex forever.
here is my loop
it's just a simple loop with some vars and delay function for example
void loop() {
if (WiFi.status() == WL_CONNECTED) {
float temp_check = dht.readTemperature();
if (temp_check == 0) {
delay(1000);
temp_check = dht.readTemperature();
}
if (temp_check > 32.0 && *cooling_switch_p == false) {
Serial.println("[ INF ] Too high temperature, switch on a cooling system");
digitalWrite(COOLING_RELAY, LOW);
*cooling_switch_p = true;
}
else if (temp_check < 30.0 && *cooling_switch_p == true) {
Serial.println("[ INF ] Normal temperature, switch off a cooling system");
digitalWrite(COOLING_RELAY, HIGH);
*cooling_switch_p = false;
}
Serial.print("[ DBG ] Light Switch: ");
Serial.println(String(light_switch));
Serial.println("");
Serial.print("[ DBG ] Pump Switch: ");
Serial.println(String(pump_switch));
Serial.println("");
delay(5000);
}
else {
Serial.println("[ ERR ] Wifi not connected. Exiting program");
delay(9999);
exit(0);
}
}
I assume you're trying to send your sensor data from this device to another one while more or less accurately maintaining the 5-second sampling interval. You can create a simple asynchronous architecture yourself using 2 threads.
The existing thread (created by Arduino) runs your current loop() which reads the sensor every 5 seconds. You add a second thread which deals with transmitting the sample to other devices. The first thread posts the sample to the second thread through a FreeRTOS queue; second thread immediately goes to work transmitting. The first thread continues to mind its own business without waiting for transmission to complete.
Using the FreeRTOS documentation on creating tasks and queues:
#include <task.h>
#include <queue.h>
#include <assert.h>
TaskHandle_t hTxTask;
QueueHandle_t hTxQueue;
constexpr size_t TX_QUEUE_LEN = 10;
// The task which transmits temperature samples to wherever needed
void txTask(void* parm) {
while (true) {
float temp;
// Block until a sample is posted to queue
const BaseType_t res = xQueueReceive(hTxQueue, static_cast<void*>(&temp), portMAX_DELAY);
assert(res);
// Here you write your code to send the temperature to other device
// e.g.: esp_now_send(temp);
}
}
void setup() {
// Create the queue
hTxQueue = xQueueCreate(TX_QUEUE_LEN, sizeof(float));
assert(hTxQueue);
// Create and start the TX task
const BaseType_t res = xTaskCreate(txTask, "TX task", 8192, nullptr, tskIDLE_PRIORITY, &hTxTask);
assert(res);
// ... rest of your setup()
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
float temp_check = dht.readTemperature();
// Post fresh sample to queue
const BaseType_t res = xQueueSendToBack(hTxQueue, &temp_check, 0);
if (!res) {
Serial.println("Error: TX queue full!");
}
// ... Rest of your loop code
}
}

Arduino .read() function interfering with BLE connection

Firstly, I want to apologize as I am new to BLE connectivity and much of Arduino programming. I am busy with a project which in involved making a smart coffee scale which can output data to a smartphone via a BLE connection. I am working with an Arduino nano 33 IoT, and an hx711 load cell amplifier.
I need to create a program where I can send and receive data to and from the Arduino to the smartphone app. I have used standard ArduinoBLE peripheral libraries such as the "BatteryMonitor" sketch and the "ButtonLED" sketch. By combining both of these example sketches together I have managed to established a connection where I can send and receive data.
The problem arises when I try to use functions within the HX711 library such as scale.read(); to retrieve values being output from the hx711 amplifier. When I use a serial read function such as scale.read() the bluetooth connection fails before establishing itself properly. I imagine this is due to the scale.read() function interfering with the serial data being transmitted and received by the Arduino, but I have no clue how to get around this problem.
I basically want to change the battery monitor output to be the output of the value read from the hx711 load cell amplifier but I am struggling to get this to work.
#include "HX711.h"
#include <ArduinoBLE.h>
HX711 scale;
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
BLEUnsignedCharCharacteristic batteryLevelChar("2A19", // standard 16-bit characteristic UUID
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
int oldBatteryLevel = 0; // last battery level reading from analog input
long previousMillis = 0; // last time the battery level was checked, in ms
const int ledPin = LED_BUILTIN; // pin to use for the LED
double val;
void setup() {
Serial.begin(9600);
scale.begin(A1, A0); //Initialized scale on these pins
while (!Serial);
scale.set_scale(432.f); // this value is obtained by calibrating the scale with known weights; see the README for details
scale.tare(); // reset the scale to 0
// set LED pin to output mode
pinMode(ledPin, OUTPUT);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
// set advertised local name and service UUID:
BLE.setLocalName("COFFEE");
BLE.setAdvertisedService(ledService);
// add the characteristic to the service
ledService.addCharacteristic(switchCharacteristic);
ledService.addCharacteristic(batteryLevelChar); // add the battery level characteristic
// add service
BLE.addService(ledService);
// set the initial value for the characeristic:
switchCharacteristic.writeValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral");
}
void loop()
{
// listen for BLE peripherals to connect:
BLEDevice central = BLE.central();
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected())
{
// Battery Monitor
// scale.read();
long currentMillis = millis();
// if 200ms have passed, check the battery level:
if (currentMillis - previousMillis >= 200) {
previousMillis = currentMillis;
// scale.read(); // This function alone will prevent the BLE connection from establishing properly.
updateBatteryLevel();
// outputScale();
}
// if the remote device wrote to the characteristic,
// use the value to control the LED:
if (switchCharacteristic.written()) {
if (switchCharacteristic.value()) { // any value other than 0
Serial.println("LED on");
digitalWrite(ledPin, HIGH); // will turn the LED on
} else { // a 0 value
Serial.println(F("LED off"));
digitalWrite(ledPin, LOW); // will turn the LED off
}
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
void updateBatteryLevel()
{
/* Read the current voltage level on the A0 analog input pin.
This is used here to simulate the charge level of a battery.
*/
int battery = analogRead(A0);
int batteryLevel = map(battery, 0, 1023, 0, 100);
if (batteryLevel != oldBatteryLevel) { // if the battery level has changed
// Serial.print("Battery Level % is now: "); // print it
Serial.println(batteryLevel);
batteryLevelChar.writeValue(batteryLevel); // and update the battery level characteristic
oldBatteryLevel = batteryLevel; // save the level for next comparison
}
}
void outputScale(){
int t, i, n, T;
double val, sum, sumsq, mean;
float stddev;
n = 20;
t = millis();
i = sum = sumsq = 0;
while (i<n) {
val = ((scale.read() - scale.get_offset()) / scale.get_scale());
sum += val;
sumsq += val * val;
i++;
}
t = millis() - t;
mean = sum / n;
stddev = sqrt(sumsq / n - mean * mean);
// Serial.print("Mean, Std Dev of "); Serial.print(i); Serial.print(" readings:\t");
Serial.print(sum / n, 3); Serial.print("\n"); // Serial.print(stddev, 3);
// Note: 2 sigma is 95% confidence, 3 sigma is 99.7%
//Serial.print("\nTime taken:\t"); Serial.print(float(t)/1000, 3); Serial.println("Secs\n");
/*
scale.power_down(); // put the ADC in sleep mode
delay(5000);
scale.power_up();
*/
}
You are initialising as scale.begin(A1, A0) while trying to read from the same A0 pin.

WebClient and MotionDetector stops after a while

I've been digging this for around a week and doesn't have any way to solve this one. My Arduino code is working for a while (few times / few days) and then stops all of a sudden. I'm trying to implement a WebClient within the Arduino which sends HTTP GET requests to some other server every time (periodically - every 90 seconds) when a motion had been detected / when motion had stopped.
Below you can find the code. Can anyone assist?
#include <Ethernet2.h>
#include <SPI.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x73, 0x88 };
IPAddress ip(192,168,20,84);
IPAddress server(192,168,50,93); // Google
IPAddress myDns(8, 8, 8, 8);
EthernetClient client;
//getMovement - sends a GET request when motion is detected
void getMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=1");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//getNoMovement - sends a GET request when motion had stopped
void getNoMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=0");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 10;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 90000;
//
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 2; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pirPin, LOW);
Ethernet.begin(mac);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
loop();
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
getMovement();
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
getNoMovement();
}
}
}
It's hard to say without a better description of symptoms.
Are the LED still blinking ?
If yes, the socket code seems wrong to me:
void getMovement() {
client.stop();
You must remember that TCP requires connection tracking, so you can't immediately stop a socket, it has to linger a bit for acknowledging packets sent.
If you look at the implementation:
void EthernetClient::stop() {
if (_sock == MAX_SOCK_NUM)
return;
[...]
}
stop() will fail if you have more than MAX_SOCK_NUM (which is 4 on your platform) opened at a time. Can this happen?
In all case, you should avoid as much as possible dynamic allocations, you should have a single function sendMovement(bool detected) that's writing the detected value (getMovement and getNoMovement are the same function, so factorize them). You should re-use the client as much as possible (avoid closing the socket and re-opening it unless you get an error from any socket function). Finally, you might want to set up an interrupt on the digital input pin (with some software debouncing) to avoid polling on it, that would release CPU, and, depending on the configuration, might release more time to process SPI messages.
If the LED are not blinking, try to comment out the SPI related code (EthernetClient's code) and check if it works (in that case, I would check the HW for errors, some of the socket code is busy looping (socket::send does this) that would never finish and stop your loop function from progressing. In that case, if you use JTAG to pause the CPU, it'll be in the client.connect or client.println method.
If it still does not work (LED not blinking with no SPI code), then the issue is likely hardware, check voltage / temperature / JTAG connect to the board to interrupt the CPU to figure out where it's struck.
BTW, if you are doing HTTP, the request is wrong and should be:
GET url HTTP/1.1\r\n
Host: yourserverhost.com\r\n
Connection: Keep-Alive\r\n
\r\n
The part HTTP/1.x after the GET url is absolutely required even for HTTP/1.0. Unless you've written your own server (in that case, there's no need to mimick HTTP), it should not work at all, not even once.

Arduino Uno to Particle Photon - Converting Code

Please bear with me. I am an amateur programmer at Arduino, and have never used Particle photon before.
I used an Arduino Uno and wrote the attached code that detects heart beat and temperature using the Grove Ear clip heart beat sensor and the Grove Temperature sensor and then prints them in the console every 20 seconds. Previously, this code was written to show in an Grove OLED screen but later simplified it back to using it without the OLED screen.
I am now looking into using the same application and function using the same sensor on a Particle Photon (as it is smaller and has WiFi capability). I have never previously used this technology before but I saw online that it, more or less, uses the same code application. I have been through the sample codes for this online available on its website but I have no idea how to convert my code for the Arduino into code for the photon (Photon console compiles the code without any error but does not show any sensor data). Can someone either point me to the right direction/ appropriate online resources / help me change this code here to make it work on the Photon? (I just added the Particle.publish() wherever I was using Arduino's Serial.println() but it still doesn't print anything).
The result in the console shows:
Please be ready
This will now begin
then it prints number 1 to 20 every second followed by sensor readings.
Again sorry for the inconvenience and thank you for your help.
I used direct codes from the documentation blog of the sensors (bottom of the page of the linked page):
Grove heart bear sensor
Grove Temperature sensor
#define LED 4//indicator, Grove - LED is connected with D4 of Arduino
boolean led_state = LOW;//state of LED, each time an external interrupt
//will change the state of LED
float tempa;
int tempPin = 0;
unsigned char counter;
unsigned long temp[21];
unsigned long sub;
bool data_effect=true;
unsigned int heart_rate;//the measurement result of heart rate
const int max_heartpluse_duty = 2000;//you can change it follow your system's request.
//2000 meams 2 seconds. System return error
//if the duty overtrip 2 second.
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(9600);
while (!Serial){
;
}
Serial.println("Please be ready");
delay(5000);
arrayInit();
Serial.println("This will now begin.");
attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
}
void loop()
{
digitalWrite(LED, led_state);//Update the state of the indicator
}
/*Function: calculate the heart rate*/
void sum()
{
if(data_effect)
{
heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time
Serial.print("Heart_rate_is:\t");
Serial.println(heart_rate);
tempa = analogRead(tempPin);
tempa = tempa * 0.11;
Serial.print("Body Temperature = ");
Serial.print(tempa);
Serial.print("*C");
Serial.println();
delay(1000);
}
data_effect=1;//sign bit
}
/*Function: Interrupt service routine.Get the sigal from the external interrupt*/
void interrupt()
{
temp[counter]=millis();
Serial.println(counter,DEC);
switch(counter)
{
case 0:
sub=temp[counter]-temp[20];
break;
default:
sub=temp[counter]-temp[counter-1];
break;
}
if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
{
data_effect=0;//sign bit
counter=0;
Serial.println("measurement error,test will restart!" );
arrayInit();
}
else if (counter==20&&data_effect)
{
counter=0;
sum();
}
else if(counter!=20&&data_effect)
{
counter++;
}
else
{
counter=0;
data_effect=1;
}
}
/*Function: Initialization for the array(temp)*/
void arrayInit()
{
for(unsigned char i=0;i < 20;i ++)
{
temp[i]=0;
}
temp[20]=millis();
}

Arduino not reading float level switch signal

Hey I am trying to set up a project at the moment, I have a float level switch connected to pin 2 of my Arduino board, the other end is connected to the 5v in on the arduino.
I want to have the software display a message when the switch goes high but at the moment it goes straight to the message and I know that the switch is not set high as I have it in my hand.
In future it will send a text message when the signal goes high, being used for flood monitoring using a float level switch.
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "sms.h"
SMSGSM sms;
//To change pins for Software Serial, use the two lines in GSM.cpp.
int numdata;
boolean started=false;
char smsbuffer[160];
char n[20];
int closed=0;//Sets initial signal to 0
const int switchPin = 2;
int switchState = 0; // current state of the button
int lastswitchState = 0; // previous state of the button
void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield for Flood Early Warning System \n");
pinMode(switchPin, INPUT);
//Start configuration of shield with baudrate.
//For http uses is recommended to use 4800 or slower.
}
void loop() {
closed=digitalRead(switchPin);
// compare the buttonState to its previous state
if (switchState != lastswitchState) {
// if the state has changed, increment the counter
if (switchState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
Serial.println("on");
} else {
// if the current state is LOW then the button
// wend from on to off:
Serial.println("off");
}
// Delay a little bit to avoid bouncing
delay(50);
}
// save the current state as the last state,
//for next time through the loop
lastswitchState = switchState;
if (closed == HIGH) {
Serial.println ("Switch signal received");
if (gsm.begin(2400)){
Serial.println("\n status=READY");
started=true;
}
else Serial.println("\n status=IDLE");
if(started){
//Enable this two lines if you want to send an SMS.
if (sms.SendSMS("0871234567", "Arduino SMS"))//Number you wish to text and the message to be sent
Serial.println("\nSMS sent OK");//Alert for Serial monitor once sms sent
}
}
}
You should connect your input pin to GND via a 10KOhm resistor. See https://www.arduino.cc/en/Tutorial/DigitalPins :
"This also means however, that pins configured as pinMode(pin, INPUT) with nothing connected to them, ... will report seemingly random changes in pin state, picking up electrical noise from the environment, or capacitively coupling the state of a nearby pin. ".
And https://www.arduino.cc/en/Reference/DigitalRead :
If the pin isn't connected to anything, digitalRead() can return either HIGH or LOW (and this can change randomly).
In other words, when your switch is open, the input pin is not in a defined state (either on or off). By adding a pulldown resistor (a 10 KOhm resistor between your input pin and GND, the resistor "pulls down" (=toward the ground) your pin, unless the switch is closed, in which case the connection to +5V prevails (because it is a direct connection, without a resistor).