Example B: Changing the Address of your SDI-12 Sensor

Communication with an SDI-12 sensor depends on its 1-character alphanumeric address (1-9, A-Z, a-z). A sensor can also be programmed with an address of 0, but that address cannot always be used to get measurements from the sensor. This sketch enables you to find and change the address of your sensor.

First, physically connect your SDI-12 sensor to your device. Some helpful hits for connecting it can be found here: https://envirodiy.org/topic/logging-mayfly-with-decagon-sdi-12-sensor/#post-2129.

Once your sensor is physically connected to your board, download this library and open this sketch.

Scroll to line 25 of the sketch (int8_t dataPin = SDI12_DATA_PIN;). Change the 7 to the pin number that your sensor is attached to. You could also define the data pin in your platformio.ini: (-D SDI12_DATA_PIN=##)

Set the pin to provide power to your sensor in line 25 (int8_t powerPin = SDI12_POWER_PIN;). If your sensor is continuously powered, set the power pin to -1.

Upload the sketch to your board. After the upload finishes, open up the serial port monitor at a baud rate of 115200 on line 53.

In the serial monitor you will see it begin scanning through all possible SDI-12 addresses. Once it has found an occupied address, it will stop and ask you to enter a new address. Send your desired address to the serial port. On the screen you should see "Readdressing Sensor." followed by "Success. Rescanning for verification." The scan will begin again, stopping at your new address. If you are now happy with the address you've selected, smile and close the serial port monitor.

If you are using a Meter Group Hydros 21 CTD sensor, change the channel to 1 in the serial monitor where prompted.

PlatformIO Configuration

1; PlatformIO Project Configuration File
2
3[platformio]
4description = SDI-12 Library Example B: Changing the SDI-12 Address of a Sensor
5src_dir = .piolibdeps/Arduino-SDI-12_ID1486/examples/b_address_change
6
7[env:mayfly]
8monitor_speed = 115200
9board = mayfly
10platform = atmelavr
11framework = arduino
12lib_ldf_mode = deep+
13lib_ignore = RTCZero
14lib_deps =
15 SDI-12

The Complete Example

1/**
2 * @example{lineno} b_address_change.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
5 * @author Kevin M.Smith <SDI12@ethosengineering.org>
6 * @date August 2013
7 *
8 * @brief Example B: Changing the Address of your SDI-12 Sensor
9 *
10 * This is a simple demonstration of the SDI-12 library for arduino.
11 * It discovers the address of the attached sensor and allows you to change it.
12 */
13
14#include <SDI12.h>
15
16#ifndef SDI12_DATA_PIN
17#define SDI12_DATA_PIN 7
18#endif
19#ifndef SDI12_POWER_PIN
20#define SDI12_POWER_PIN 22
21#endif
22
23uint32_t serialBaud = 57600; /*!< The baud rate for the output serial port */
24int8_t dataPin = SDI12_DATA_PIN; /*!< The pin of the SDI-12 data bus */
25int8_t powerPin = SDI12_POWER_PIN; /*!< The sensor power pin (or -1) */
26uint32_t wake_delay = 0; /*!< Extra time needed for the sensor to wake (0-100ms) */
27
28/** Define the SDI-12 bus */
29SDI12 mySDI12(dataPin);
30
31String myCommand = ""; // empty to start
32char oldAddress = '!'; // invalid address as placeholder
33
34/**
35 * @brief gets identification information from a sensor, and prints it to the serial
36 * port
37 *
38 * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'.
39 */
40void printInfo(char i) {
41 String command = "";
42 command += (char)i;
43 command += "I!";
44 mySDI12.sendCommand(command, wake_delay);
45 delay(30);
46
47 String sdiResponse = mySDI12.readStringUntil('\n');
48 sdiResponse.trim();
49 // allccccccccmmmmmmvvvxxx...xx<CR><LF>
50 Serial.print(sdiResponse.substring(0, 1)); // address
51 Serial.print(", ");
52 Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number
53 Serial.print(", ");
54 Serial.print(sdiResponse.substring(3, 11)); // vendor id
55 Serial.print(", ");
56 Serial.print(sdiResponse.substring(11, 17)); // sensor model
57 Serial.print(", ");
58 Serial.print(sdiResponse.substring(17, 20)); // sensor version
59 Serial.print(", ");
60 Serial.print(sdiResponse.substring(20)); // sensor id
61 Serial.print(", ");
62}
63
64// this checks for activity at a particular address
65// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z'
66bool checkActive(byte i) { // this checks for activity at a particular address
67 Serial.print("Checking address ");
68 Serial.print((char)i);
69 Serial.print("...");
70 myCommand = "";
71 myCommand += (char)i; // sends basic 'acknowledge' command [address][!]
72 myCommand += "!";
73
74 for (int j = 0; j < 3; j++) { // goes through three rapid contact attempts
75 mySDI12.sendCommand(myCommand, wake_delay);
76 delay(30);
77 if (mySDI12.available()) { // If we hear anything, assume we have an active sensor
78 Serial.println("Occupied");
79 mySDI12.clearBuffer();
80 return true;
81 } else {
82 Serial.println("Vacant"); // otherwise it is vacant.
83 mySDI12.clearBuffer();
84 }
85 }
86 return false;
87}
88
89void setup() {
90 Serial.begin(serialBaud);
91 while (!Serial && millis() < 10000L);
92
93 Serial.println("Opening SDI-12 bus...");
94 mySDI12.begin();
95 delay(500); // allow things to settle
96
97 Serial.println("Timeout value: ");
98 Serial.println(mySDI12.TIMEOUT);
99
100 // Power the sensors;
101 if (powerPin >= 0) {
102 Serial.println("Powering up sensors, wait 30s...");
103 pinMode(powerPin, OUTPUT);
104 digitalWrite(powerPin, HIGH);
105 delay(30000L);
106 }
107}
108
109void loop() {
110 boolean found = false; // have we identified the sensor yet?
111
112 for (byte i = '0'; i <= '9'; i++) { // scan address space 0-9
113 if (found) break;
114 if (checkActive(i)) {
115 found = true;
116 oldAddress = i;
117 printInfo(i);
118 }
119 }
120
121 for (byte i = 'a'; i <= 'z'; i++) { // scan address space a-z
122 if (found) break;
123 if (checkActive(i)) {
124 found = true;
125 oldAddress = i;
126 printInfo(i);
127 }
128 }
129
130 for (byte i = 'A'; i <= 'Z'; i++) { // scan address space A-Z
131 if (found) break;
132 if (checkActive(i)) {
133 found = true;
134 oldAddress = i;
135 printInfo(i);
136 }
137 }
138
139 if (!found) {
140 Serial.println(
141 "No sensor detected. Check physical connections."); // couldn't find a sensor.
142 // check connections..
143 while (1) // die
144 ;
145 } else {
146 Serial.print("Sensor active at address "); // found a sensor!
147 Serial.print(oldAddress);
148 Serial.println(".");
149
150 Serial.println("Enter new address."); // prompt for a new address
151 while (!Serial.available());
152 char newAdd = Serial.read();
153
154 // wait for valid response
155 while (((newAdd < '0') || (newAdd > '9')) && ((newAdd < 'a') || (newAdd > 'z')) &&
156 ((newAdd < 'A') || (newAdd > 'Z'))) {
157 if (!(newAdd == '\n') || (newAdd == '\r') || (newAdd == ' ')) {
158 Serial.println(
159 "Not a valid address. Please enter '0'-'9', 'a'-'A', or 'z'-'Z'.");
160 }
161 while (!Serial.available());
162 newAdd = Serial.read();
163 }
164
165 /* the syntax of the change address command is:
166 [currentAddress]A[newAddress]! */
167
168 Serial.println("Readdressing sensor.");
169 myCommand = "";
170 myCommand += (char)oldAddress;
171 myCommand += "A";
172 myCommand += (char)newAdd;
173 myCommand += "!";
174 mySDI12.sendCommand(myCommand);
175
176 /* wait for the response then throw it away by
177 clearing the buffer with clearBuffer() */
178 delay(300);
179 mySDI12.clearBuffer();
180
181 Serial.println("Success. Rescanning for verification.");
182 }
183}