Skip to content

Divers

/**
   @file RAK13010_SDI_12_Check_All_Addresses.ino
   @author rakwireless.com
   @brief  Check all Addresses for Active Sensors and Print Status.
           It discovers the address of all sensors active and attached to the board.
           THIS CAN BE *REALLY* SLOW TO RUN!!!
           Each sensor should have a unique address already - if not, multiple sensors may
           respond simultaenously to the same request and the output will not be readable
           by the Arduino.
   @version 0.1
   @date 2022-03-11
   @copyright Copyright (c) 2022
**/
#include "RAK13010_SDI12.h" // Click to install library: // Click to install library: http://librarymanager/All#RAK13010

#define TX_PIN WB_IO6 // The pin of the SDI-12 data bus.
#define RX_PIN WB_IO5 // The pin of the SDI-12 data bus.
#define OE WB_IO4     // Output enable pin, active low.

RAK_SDI12 mySDI12(RX_PIN, TX_PIN, OE);

/**
 * @brief Gets identification information from a sensor, and prints it to the serial port expects.
 * @param i A character between '0'-'9'
 */
void printInfo(char i) 
{
  String command = "";
  command += (char)i;
  command += "I!";
  Serial.println(command);
  mySDI12.sendCommand(command);
  mySDI12.clearBuffer();
  delay(30);

  Serial.print("  --");
  Serial.print(i);
  Serial.print("--  ");

  while (mySDI12.available()) 
  {
    Serial.write(mySDI12.read());
    delay(10);  // 1 character ~ 7.5ms.
  }
}

/**
 * @brief this checks for activity at a particular address.
 * @param i A character between '0'-'9'
 */
boolean checkActive(char i) 
{
  String myCommand = "";
  myCommand        = "";
  myCommand += (char)i;  // Sends basic 'acknowledge' command [address][!].
  myCommand += "!";

  for (int j = 0; j < 3; j++) 
  {
//    Serial.printf("sdi.sendCommand(myCommand);\r\n");
//    delay(100);
    mySDI12.sendCommand(myCommand);
    mySDI12.clearBuffer();
    delay(30);
    if (mySDI12.available()) 
    {
      return true;
    }
  }
  mySDI12.clearBuffer();
  return false;
}

void scanAddressSpace(void) 
{
  for (char i = '0'; i <= '9'; i++) // Scan address space 0-9.
  {
    Serial.printf("Scan Address Space = %c\r\n",i);
    if (checkActive(i)) 
    { 
      printInfo(i); 
    }
  }


}

void setup() 
{
  pinMode(WB_IO2, OUTPUT);
  digitalWrite(WB_IO2, HIGH);  // Power the sensors.

  // Initialize Serial for debug output.
  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }
  Serial.println("Start Search for SDI-12 Devices.");

  mySDI12.begin();
  delay(500);
  scanAddressSpace();
  mySDI12.end();

  Serial.println("End Search for SDI-12 Devices.");

  digitalWrite(WB_IO2, LOW); // Cut power.
}

void loop() 
{
  delay(100);
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
#include <lib.h>
#include <Arduino.h>
#include <Wire.h>



#include "RAK13010_SDI12.h"
#include "Melopero_RV3028.h" //http://librarymanager/All#Melopero_RV3028  bibliothèque pour le RTC
#include <time.h>       /* time_t, struct tm, time, mktime */
#include "timestamp32bits.h"

// Comment the next line if you want DEBUG output. But the power savings are not as good then!!!!!!!
//#define MAX_SAVE

//define time interval measurement 
#define SDI12_sensor_PERIOD (15000)  //timer 600000 (10min)



#define TX_PIN WB_IO6  // The pin of the SDI-12 data bus.
#define RX_PIN WB_IO5  // The pin of the SDI-12 data bus.
#define OE WB_IO4      // Output enable pin, active low.


#define PIN_VBAT WB_A0
uint32_t vbat_pin = PIN_VBAT;

#define PIN_LORA_DIO_1 47             // DIO1 GPIO pin for RAK4631



typedef struct __attribute__ ((__packed__)) { 

  float level;  
  float conductivity;
  float temperature_CTD;
  float batteryVoltage;
  uint8_t time_sep[8]; 
} SensorDataStruct;  // sensor_data_t

SensorDataStruct sensor;  // creation of the payload structure

//uint8_t time_sep[8];


timestamp32bits stamp = timestamp32bits();


int sensor_address =0;
Melopero_RV3028 rtc;


RAK_SDI12 mySDI12(RX_PIN, TX_PIN, OE);

String sdiResponse = "";

String sdiResponse1 = "";
int sdiCommandIndex = 1;
String sdiCommand = "M!";
String sdiCommand1= "D0!";
//float readVBAT(void);
void readFromSensor(int sensor_address);
void uplink_routine();
void parseResponse(String response, int sensor_address);



/*************************************

   LoRaWAN band setting:
     RAK_REGION_EU433
     RAK_REGION_CN470
     RAK_REGION_RU864
     RAK_REGION_IN865
     RAK_REGION_EU868
     RAK_REGION_US915
     RAK_REGION_AU915
     RAK_REGION_KR920
     RAK_REGION_AS923

 *************************************/
#define PROJET_NODE_BAND (RAK_REGION_EU868)
#define PROJET_NODE_DEVEUI \
  { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x0C, 0xC1, 0x0E } 
#define PROJET_NODE_APPEUI \
  { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x0C, 0xC1, 0x0E }
#define PROJET_NODE_APPKEY \
  { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3E }



/** Packet buffer for sending */
uint8_t collected_data[64] = { 0 };

void recvCallback(SERVICE_LORA_RECEIVE_T *data) {
  if (data->BufferSize > 0) {
    Serial.println("Something received!");
    for (int i = 0; i < data->BufferSize; i++) {
      Serial.printf("%x", data->Buffer[i]);
    }
    Serial.print("\r\n");
  }
}

void joinCallback(int32_t status) {
  Serial.printf("Join status: %d\r\n", status);
}

void sendCallback(int32_t status) {
  if (status == 0) {
    Serial.println("Successfully sent");
  } else {
    Serial.println("Sending failed");
  }
}

void setup() {
  Serial.begin(115200, RAK_AT_MODE);
  delay(2000);

   Wire.begin();   //I2C RTC

rtc.initI2C(); // First initialize and create the rtc device
rtc.writeToRegister(0x35,0x00);  
rtc.writeToRegister(0x37,0xB4); //Direct Switching Mode (DSM): when VDD < VBACKUP, switchover occurs from VDD to VBACKUP
rtc.set24HourMode();  // Set the device to use the 24hour format (default) instead of the 12 hour format
rtc.setTime(2024, 1, 10, 30, 18, 50, 00);


  Serial.println("RAKwireless SDI12 sensor");
  Serial.println("------------------------------------------------------");



  // OTAA Device EUI MSB first
  uint8_t node_device_eui[8] = PROJET_NODE_DEVEUI;
  // OTAA Application EUI MSB first
  uint8_t node_app_eui[8] = PROJET_NODE_APPEUI;
  // OTAA Application Key MSB first
  uint8_t node_app_key[16] = PROJET_NODE_APPKEY;

  if (!api.system.lpm.set(1)) {
    Serial.printf("LoRaWan SDI12 sensor - set low power mode is incorrect! \r\n");
    return;
  }

  if (!api.lorawan.nwm.set(1)) {
    Serial.printf("LoRaWan SDI12 sensor - set network working mode is incorrect! \r\n");
    return;
  }

  if (!api.lorawan.appeui.set(node_app_eui, 8)) {
    Serial.printf("LoRaWan SDI12 sensor - set application EUI is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.appkey.set(node_app_key, 16)) {
    Serial.printf("LoRaWan SDI12 sensor - set application key is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.deui.set(node_device_eui, 8)) {
    Serial.printf("LoRaWan SDI12 sensor - set device EUI is incorrect! \r\n");
    return;
  }

  if (!api.lorawan.band.set(PROJET_NODE_BAND)) {
    Serial.printf("LoRaWan SDI12 sensor - set band is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)) {
    Serial.printf("LoRaWan SDI12 sensor - set device class is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.njm.set(RAK_LORA_OTAA))  // Set the network join mode to OTAA
  {
    Serial.printf("LoRaWan SDI12 sensor - set network join mode is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.join())  // Join to Gateway
  {
    Serial.printf("LoRaWan SDI12 sensor - join fail! \r\n");
    return;
  }

  Serial.println("++++++++++++++++++++++++++");
  Serial.println("SDI12 sensor");
  Serial.println("++++++++++++++++++++++++++");


  /** Wait for Join success */
  while (api.lorawan.njs.get() == 0) {
    Serial.print("Wait for LoRaWAN join...");
    api.lorawan.join();
    delay(10000); //10000
  }

  if (!api.lorawan.adr.set(true)) {
    Serial.printf("LoRaWan SDI12 sensor - set adaptive data rate is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.rety.set(1)) {
    Serial.printf("LoRaWan SDI12 sensor - set retry times is incorrect! \r\n");
    return;
  }
  if (!api.lorawan.cfm.set(1)) {
    Serial.printf("LoRaWan SDI12 sensor - set confirm mode is incorrect! \r\n");
    return;
  }

  /** Check LoRaWan Status*/
  Serial.printf("Duty cycle is %s\r\n", api.lorawan.dcs.get() ? "ON" : "OFF");             // Check Duty Cycle status
  Serial.printf("Packet is %s\r\n", api.lorawan.cfm.get() ? "CONFIRMED" : "UNCONFIRMED");  // Check Confirm status
  uint8_t assigned_dev_addr[4] = { 0 };
  api.lorawan.daddr.get(assigned_dev_addr, 4);
  Serial.printf("Device Address is %02X%02X%02X%02X\r\n", assigned_dev_addr[0], assigned_dev_addr[1], assigned_dev_addr[2], assigned_dev_addr[3]);  // Check Device Address
  Serial.printf("Uplink period is %ums\r\n", SDI12_sensor_PERIOD);
  Serial.println("");
  api.lorawan.registerRecvCallback(recvCallback);
  api.lorawan.registerJoinCallback(joinCallback);
  api.lorawan.registerSendCallback(sendCallback);
  if (api.system.timer.create(RAK_TIMER_0, (RAK_TIMER_HANDLER)uplink_routine, RAK_TIMER_PERIODIC) != true) {
    Serial.printf("LoRaWan SDI12 sensor - Creating timer failed.\r\n");
    return;
  }
  if (api.system.timer.start(RAK_TIMER_0, SDI12_sensor_PERIOD, NULL) != true) {
    Serial.printf("LoRaWan SDI12 sensor - Starting timer failed.\r\n");
    return;
  }
}

void uplink_routine() {

uint32_t time_sensor=(uint32_t)(stamp.timestamp((rtc.getYear()-2000),rtc.getMonth(),rtc.getDate(),rtc.getHour(),rtc.getMinute(),rtc.getSecond()));

#ifndef MAX_SAVE
Serial.println(String(time_sensor));
#endif

 for(int8_t j=0; j<4; j++)
    {
      sensor.time_sep[j]=((time_sensor >> j*8) & 0xFF);
    }

#ifndef MAX_SAVE
Serial.println(sensor.time_sep[0],HEX);
Serial.println(sensor.time_sep[1],HEX);
Serial.println(sensor.time_sep[2],HEX);
Serial.println(sensor.time_sep[3],HEX);

uint32_t test=sensor.time_sep[0] | sensor.time_sep[1]<<8 | sensor.time_sep[2]<<16 | sensor.time_sep[3]<<24;


Serial.println(String(test));
#endif


readFromSensor(sensor_address);  //read sensor CTD10  SDI_adress=5

sensor.batteryVoltage = (int)(readVBAT()*100);

   /** Cayenne Low Power Payload */
  uint8_t data_len = 0;

  collected_data[data_len++] = highByte((int)sensor.level);
  collected_data[data_len++] = lowByte((int)sensor.level);
  collected_data[data_len++] = highByte((int)sensor.temperature_CTD);
  collected_data[data_len++] = lowByte((int)sensor.temperature_CTD);
  collected_data[data_len++] = highByte((int)sensor.conductivity);
  collected_data[data_len++] = lowByte((int)sensor.conductivity);
  collected_data[data_len++] = highByte((int)sensor.batteryVoltage);
  collected_data[data_len++] = lowByte((int)sensor.batteryVoltage);


  collected_data[data_len++] = sensor.time_sep[0];
  collected_data[data_len++] = sensor.time_sep[1];
  collected_data[data_len++] = sensor.time_sep[2];
  collected_data[data_len++] = sensor.time_sep[3];


  Serial.println("Data Packet:");
  for (int i = 0; i < data_len; i++) {
    Serial.printf("0x%02X ", collected_data[i]);
  }
  Serial.println("");


  /** Send the data package */
  if (api.lorawan.send(data_len, (uint8_t *)&collected_data, 2, true, 1)) {
    Serial.println("Sending is requested");
  } else {
    Serial.println("Sending failed");
  }
}


float readVBAT(void)
{
  // Set the analog reference to 3.0V (default = 3.6V)
  analogReference(AR_INTERNAL_3_0);
  // Set the resolution to 12-bit (0..4095)
  analogReadResolution(12); // Can be 8, 10, 12 or 14
  // Let the ADC settle
  delay(1);
  float raw;
  // Get the raw 12-bit, 0..3000mV ADC value
  raw = analogRead(vbat_pin);
  //return raw * REAL_VBAT_MV_PER_LSB;
  return raw * (3.0/4096)*1.73;
}

void readFromSensor(int sensor_address) {
  // Power the sensor.
  pinMode(WB_IO2, OUTPUT);
  digitalWrite(WB_IO2, HIGH);
  delay(500); //1500


  mySDI12.begin();
  delay(50); //500

sdiResponse="";

  mySDI12.clearBuffer();
  delay(50);  //500
  mySDI12.sendCommand(String(sensor_address) + sdiCommand);


 delay(700); //700 pour ATMOS14, GS3, ECH20 


  mySDI12.clearBuffer();
  //sdiResponse="";
 //delay(100);
 mySDI12.sendCommand(String(sensor_address) + sdiCommand1);

delay(500);



 sdiResponse = mySDI12.readStringUntil('\n');

 #ifndef MAX_SAVE
  Serial.println("D:" + sdiResponse);
 #endif  

parseResponse(sdiResponse,sensor_address);

  mySDI12.end();

  digitalWrite(WB_IO2, LOW);
}

void parseResponse(String response, int sensor_address) {

  int index = 0;
  int nextIndex = 0;
  int counter = 0;
  String value = "";
  while (index < response.length()) {
    nextIndex = response.indexOf('+', index);

    // If no other "+" sign is found, get the rest of the string.
    if (nextIndex == -1) {
      nextIndex = response.length();
    }

    value = response.substring(index, nextIndex);
    //Serial.println(value);

    switch (sensor_address) {

     case 0 :

             switch (counter) {
              case 0:
                // Address of the sensor
                break;
              case 1:
                sensor.level = (value.toFloat()*100);
              #ifndef MAX_SAVE
                Serial.print(String(value.toFloat()) +",");
              #endif 
                break;
              case 2:
                sensor.temperature_CTD= (value.toFloat()*10);
              #ifndef MAX_SAVE
                Serial.print(String(value.toFloat())+",");
              #endif
                break;
              case 3:
               sensor.conductivity= (value.toFloat());
              #ifndef MAX_SAVE
                Serial.print(String(value.toFloat())+",");
              #endif
                break;

              default:
                break;
            }
       break;     
    }

    index = nextIndex + 1;
    counter = counter + 1;
  }
   #ifndef MAX_SAVE
  Serial.println(sensor.batteryVoltage);
  #endif
}

void loop() {
  /* Destroy this busy loop and use timer to do what you want instead,
     * so that the system thread can auto enter low power mode by api.system.lpm.set(1); */
  api.system.scheduler.task.destroy();
}