Components and supplies
Arduino MKR GSM 1400
Cable gland for strain relief and water proofing
6-24V 12V/24V to 5V 3A CAR USB Charger Module DC Buck step down Converter
JSN-SR04T
Lithium Ion Battery - 3.7v 2000mAh
Cable gland for strain relief and waterproofing
SIM card, data-only
DHT22 Temperature Sensor
Waterproof Enclosure
3 Conductor 22AWG Stranded 100 Ft Shielded PVC
USB-A to Micro-USB Cable
Solderless Breadboard Half Size
Water Sensor
Apps and platforms
Thinger.io Platform
Project description
Code
2 Arudino sketch for remote monitoring with Thinger.io: has ultrasonic sensor, no BMV
arduino
I have this running on an Arduino MKR GSM 1400 with a data-only SIM card. You need to adapt the communication specifics for your SIM. And you need a thinger.io account or to replace the relevant code with appropriate bits for your IoT server.
1// library name // for... 2#include <Arduino.h> // these first 3 lines were added to stop the complier from complaining about min and max macros that are used somewhere in the included files 3#undef max // I can probably remove them at some point when libraries are updated. I had not explicitly called Arduino.h before. [Still needed May 2020] 4#undef min 5 6#include <MKRGSM.h> // GSM communication, from Arduino (Library Manager) 7#include <ThingerMKRGSM.h> // thinger.io, from thinger.io (Library Manager) 8#include <DHT.h> // temperature sensor, from Adafruit (Library Manager) 9#include <ArduinoLowPower.h> // sleep for SAMD MCUs, from Arduino (Library Manager) 10//#include <WDTZero.h> // WatchDog functionality for Arduino Zero, MKRZero and MKR1000 only, allow MINUTES of watchdog time https://github.com/javos65/WDTZero/tree/master/WDTZero 11 12#define sleep_minutes 5 13// have I tried deepSleep? 14 15// Only print to the serial monitor when debug is on 16#define DEBUG 0 17#ifdef DEBUG 18 #define DEBUG_PRINTLN(x) Serial.println(x) 19 #define DEBUG_PRINT(x) Serial.print(x) 20#else 21 #define DEBUG_PRINTLN(x) 22#endif 23 24// Thinger.io credentials 25#define USERNAME "xxxxxxxx" 26#define DEVICE_ID "yyyyyyyyy" 27#define DEVICE_CREDENTIAL "zzzzzzzzz" 28#define GPRS_APN "h2g2" // Get onto Google Fi network 29ThingerMKRGSM thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); 30 31// Temp/RH initiliazation 32#define DHTPIN 6 // digital pin sensor is connected to 33#define DHTTYPE DHT22 // which DHT sensor? 11 or 22? 34DHT dht(DHTPIN, DHTTYPE); 35 36// Water sensors digital wet or dry type 37#define highBilge 3 // digital pin the sensor is connected to 38#define lowBilge 4 // digital pin the sensor is connected to 39#define engineRoom 5 // digital pin the sensor is connected to 40 41// Bilge depth ultrasonic sensor 42#include <NewPing.h> 43#define TRIGGER_PIN 1 // Arduino pin tied to trigger pin on the ultrasonic sensor 44#define ECHO_PIN 2 // Arduino pin tied to echo pin on the ultrasonic sensor 45#define MAX_DISTANCE 150 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm. 46#define measurements_to_average 10 47NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance. 48 49// Bilge pump sensor sensor 50//static const char BILGE_SWITCH = 1; // digital pin connected to bilge pump switch through voltage divider 51 52boolean endpointRateLimiter = 1; 53 54//WDTZero WatchDoggy; // Define WDTZero as WDT 55 56void setup() { 57 Serial.begin(115200); 58 DEBUG_PRINTLN("Starting setup"); 59 60// Serial1.begin(19200); // In jepefe's code, for Arduinos without hardware serial, this would be Victron.begin(19200) 61 // and Victron was defined above by its pins and SoftwareSerial. Apparently it has been deprecated in favor of NewSoftSerial 62 // this website has plain and direct language about this, which is rarely discussed in discussions I have seen about 63 // downstream use of the serials. https://www.pjrc.com/teensy/td_libs_SoftwareSerial.html 64 65 thing.set_apn(GPRS_APN); 66 67 // set builtin led to output and turn it off 68 pinMode(LED_BUILTIN, OUTPUT); 69 digitalWrite(LED_BUILTIN, LOW); 70 71 // setup pins for ultrasonic sensor: use internal pullup resistor for echo pin 72 pinMode(TRIGGER_PIN,OUTPUT); 73 pinMode(ECHO_PIN,INPUT_PULLUP); 74 75 // Thinger.io resources 76 //thing["led"] << digitalPin(LED_BUILTIN); 77 // pin control example over internet (i.e. turning on/off a light, a relay, etc) 78 //thing["relay"] << digitalPin(7); //change this to the right pin when connecting the relay 79 80 //Temperature and RH sensor setup 81 dht.begin(); 82 83 // Wake from sleep on water detected 84 // add one for the depth from the prox sensor if/when it operates reliably 85 LowPower.attachInterruptWakeup(highBilge, NULL, LOW); 86 LowPower.attachInterruptWakeup(engineRoom, NULL, LOW); 87 LowPower.attachInterruptWakeup(lowBilge, NULL, LOW); 88 89 //pinMode(BILGE_SWITCH, INPUT_PULLUP); 90 91 delay(10000); //give a chance to reprogram 92 93 // Set up a watchdog timer, long to allow communications with thinger, which take more than 16 seconds, but sometimes do hang and need a reset 94 //WatchDoggy.setup(WDT_SOFTCYCLE16M); // initialize WDT-softcounter refesh cycle on 16 minutes interval 95 96 DEBUG_PRINTLN("Setup Complete."); 97} 98 99void loop() { 100 101 DEBUG_PRINTLN("Entering main loop, starting thinger.handle."); 102 digitalWrite(LED_BUILTIN, LOW); // turn LED back off when returning to loop 103 104 digitalWrite(LED_BUILTIN, HIGH); // LED comes on for thinger.handle 105 // Clear the watchdog timer 106 //WatchDoggy.clear(); 107 thing.handle(); // LED is on 7-8 seconds, then off for ~15 seconds for the rest of the loop 108 //WatchDoggy.clear(); // Clear the watchdog timer 109 digitalWrite(LED_BUILTIN, LOW); // LED comes off when finished with thinger.handle 110 DEBUG_PRINTLN("thinger.handle done."); 111 112 113 // these declarations are not needed for DHT or thinger, but I'm 114 // them to get integers and avoid using overly precise data 115 byte humidity = dht.readHumidity(); 116 int8_t fahrenheit = dht.readTemperature(true); 117 118 byte bilge_depth = get_bilge_depth(); 119 120 // check for high water, call endpoint to send email if detected (call once 121 if ((digitalRead(highBilge) == LOW 122 || digitalRead(lowBilge) == LOW 123 || digitalRead(engineRoom) == LOW 124 || bilge_depth > 20) 125 && endpointRateLimiter) { 126 digitalWrite(LED_BUILTIN, HIGH); //LED comes on when water detected 127 DEBUG_PRINTLN("water sensor check positive!"); 128 pson data; 129 data["water high bilge"] = digitalRead(highBilge); 130 data["water low bilge"] = digitalRead(lowBilge); 131 data["water engine room"] = digitalRead(engineRoom); 132 data["bilge water depth"] = bilge_depth; 133 thing.call_endpoint("WaterDetectedEmail", data); 134 endpointRateLimiter = 0; 135 } 136 else {digitalWrite(LED_BUILTIN, LOW); 137 DEBUG_PRINTLN("water sensor check clear.");} 138 139 // bilge pump run timer 140 /* static unsigned long bilge_timer = millis(); 141 static unsigned long bilgeTimeHigh = 0; //[seconds] 142 // check bilge pump 143 if (diintgitalRead(BILGE_SWITCH) == LOW) // Bilge switch activated by high water 144 { 145 if (millis() - bilge_timer > 1000) // Count every second water is high 146 { bilge_timer = millis(); 147 bilgeTimeHigh++; } 148 } 149 else {bilge_timer = millis();} 150 */ 151 152 pson data; 153 //data["bilge pump time"] = bilgeTimeHigh; 154 data["humidity"] = humidity; 155 //data["celsius"] = celsius; 156 data["fahrenheit"] = fahrenheit; 157 data["water high bilge"] = digitalRead(highBilge); 158 data["water low bilge"] = digitalRead(lowBilge); 159 data["water engine room"] = digitalRead(engineRoom); 160 data["bilge water depth"] = bilge_depth; 161 162 // Print the data to the Serial monitor when debugging 163 DEBUG_PRINTLN("about to write data to thinger bucket"); 164 //DEBUG_PRINT("Current:"); 165 //DEBUG_PRINTLN(Current); 166 //DEBUG_PRINT("Voltage:"); 167 //DEBUG_PRINTLN(Voltage); 168 //DEBUG_PRINT("SOC:"); 169 //DEBUG_PRINTLN(SOC); 170 DEBUG_PRINT("Humidity:"); 171 DEBUG_PRINTLN(humidity); 172 DEBUG_PRINT("Temperature (F):"); 173 DEBUG_PRINTLN(fahrenheit); 174 DEBUG_PRINT("Water in bilge (cm):"); 175 DEBUG_PRINTLN(bilge_depth); 176 177 thing.write_bucket("BoatMonitorDataBucket", data); //died here a couple times 178 DEBUG_PRINTLN("Wrote data to thinger bucket, now to sleep!"); 179 180 // Sleep 181 // Shut stuff off // test the power savings of these and uncomment or remove them 182 // USBDevice.detach(); // Is this just communcations? What is power is coming in through USB? 183 /* Serial.end(); 184 Serial1.end(); 185 digitalWrite(LED_BUILTIN, LOW); 186 */ 187 thing.stop(); //this seems to prevent thinger.handle hanging. https://community.thinger.io/t/problem-with-gsm-900a/1874 188 //sleep for this many minutes (minutes * milliseconds in a minute) 189 LowPower.sleep(sleep_minutes * 60000); 190 191 // Turn stuff back on 192 // USBDevice.attach(); // remove this when finished testing to save a little power? 193 /*Serial.begin(115200); 194 Serial1.begin(19200); 195 */ 196 DEBUG_PRINTLN("Woke up!"); 197} 198 199// Ultrasonic proxmity sensor function 200//int8_t 201byte get_bilge_depth() { 202 // I considered a DHT provide the temp and RH in the bilge. While it wouldn't change quickly, it would change with lake temp over the summer 203 // and drastically when hauled out - but that would only cause a ~2cm difference in the result so I'll save the pins and complication 204 float celsius = 18; // dht.readTemperature(); 205 float humidity = 75; //dht.readHumidity(); 206 float sound_speed = (331.4 + (0.606 * celsius) + (0.0124* humidity))/10000; // speed of sound in cm/ms adjusted for temperature and humidity 207 float duration = sonar.ping_median(measurements_to_average, MAX_DISTANCE); 208 byte distance = (duration / 2) * sound_speed; 209 byte bilge_depth = 74 - distance; // Sensor is mounted 74 cm above the bilge floor 210 return bilge_depth; 211} 212 213 214/* 215void InterruptWake() // Interrupt routine, not currently called by the interrupts 216{ 217 digitalWrite(LED_BUILTIN, HIGH); //turn on the LED when woken. Can remove all the LED 218 // parts of the RTC/Sleep system when the sketch is done to save that power, or no leave 219 // it for confirming operation. But would I watch the LED for 20 minutes to see if it lights? 220 221 //Keep Interrupt routine short, but this is an alarm. Either trigger it here or in Thinger 222}*/ 223 224/* 225void dummy() { 226 // This function will be called once on device wakeup 227 boolean endpointRateLimiter = 1; // The copy of this at the top means one email per cold start, this one means one per wake 228 // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context 229} 230*/ 231 232/* 233void myshutdown() 234{ 235 could put something here that runs before the watchdog reset 236}*/
2 Arudino sketch for remote monitoring with Thinger.io: has ultrasonic sensor, no BMV
arduino
I have this running on an Arduino MKR GSM 1400 with a data-only SIM card. You need to adapt the communication specifics for your SIM. And you need a thinger.io account or to replace the relevant code with appropriate bits for your IoT server.
1// library name // for... 2#include <Arduino.h> // these first 3 lines were added to stop the complier from complaining about min and max macros that are used somewhere in the included files 3#undef max // I can probably remove them at some point when libraries are updated. I had not explicitly called Arduino.h before. [Still needed May 2020] 4#undef min 5 6#include <MKRGSM.h> // GSM communication, from Arduino (Library Manager) 7#include <ThingerMKRGSM.h> // thinger.io, from thinger.io (Library Manager) 8#include <DHT.h> // temperature sensor, from Adafruit (Library Manager) 9#include <ArduinoLowPower.h> // sleep for SAMD MCUs, from Arduino (Library Manager) 10//#include <WDTZero.h> // WatchDog functionality for Arduino Zero, MKRZero and MKR1000 only, allow MINUTES of watchdog time https://github.com/javos65/WDTZero/tree/master/WDTZero 11 12#define sleep_minutes 5 13// have I tried deepSleep? 14 15// Only print to the serial monitor when debug is on 16#define DEBUG 0 17#ifdef DEBUG 18 #define DEBUG_PRINTLN(x) Serial.println(x) 19 #define DEBUG_PRINT(x) Serial.print(x) 20#else 21 #define DEBUG_PRINTLN(x) 22#endif 23 24// Thinger.io credentials 25#define USERNAME "xxxxxxxx" 26#define DEVICE_ID "yyyyyyyyy" 27#define DEVICE_CREDENTIAL "zzzzzzzzz" 28#define GPRS_APN "h2g2" // Get onto Google Fi network 29ThingerMKRGSM thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); 30 31// Temp/RH initiliazation 32#define DHTPIN 6 // digital pin sensor is connected to 33#define DHTTYPE DHT22 // which DHT sensor? 11 or 22? 34DHT dht(DHTPIN, DHTTYPE); 35 36// Water sensors digital wet or dry type 37#define highBilge 3 // digital pin the sensor is connected to 38#define lowBilge 4 // digital pin the sensor is connected to 39#define engineRoom 5 // digital pin the sensor is connected to 40 41// Bilge depth ultrasonic sensor 42#include <NewPing.h> 43#define TRIGGER_PIN 1 // Arduino pin tied to trigger pin on the ultrasonic sensor 44#define ECHO_PIN 2 // Arduino pin tied to echo pin on the ultrasonic sensor 45#define MAX_DISTANCE 150 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm. 46#define measurements_to_average 10 47NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance. 48 49// Bilge pump sensor sensor 50//static const char BILGE_SWITCH = 1; // digital pin connected to bilge pump switch through voltage divider 51 52boolean endpointRateLimiter = 1; 53 54//WDTZero WatchDoggy; // Define WDTZero as WDT 55 56void setup() { 57 Serial.begin(115200); 58 DEBUG_PRINTLN("Starting setup"); 59 60// Serial1.begin(19200); // In jepefe's code, for Arduinos without hardware serial, this would be Victron.begin(19200) 61 // and Victron was defined above by its pins and SoftwareSerial. Apparently it has been deprecated in favor of NewSoftSerial 62 // this website has plain and direct language about this, which is rarely discussed in discussions I have seen about 63 // downstream use of the serials. https://www.pjrc.com/teensy/td_libs_SoftwareSerial.html 64 65 thing.set_apn(GPRS_APN); 66 67 // set builtin led to output and turn it off 68 pinMode(LED_BUILTIN, OUTPUT); 69 digitalWrite(LED_BUILTIN, LOW); 70 71 // setup pins for ultrasonic sensor: use internal pullup resistor for echo pin 72 pinMode(TRIGGER_PIN,OUTPUT); 73 pinMode(ECHO_PIN,INPUT_PULLUP); 74 75 // Thinger.io resources 76 //thing["led"] << digitalPin(LED_BUILTIN); 77 // pin control example over internet (i.e. turning on/off a light, a relay, etc) 78 //thing["relay"] << digitalPin(7); //change this to the right pin when connecting the relay 79 80 //Temperature and RH sensor setup 81 dht.begin(); 82 83 // Wake from sleep on water detected 84 // add one for the depth from the prox sensor if/when it operates reliably 85 LowPower.attachInterruptWakeup(highBilge, NULL, LOW); 86 LowPower.attachInterruptWakeup(engineRoom, NULL, LOW); 87 LowPower.attachInterruptWakeup(lowBilge, NULL, LOW); 88 89 //pinMode(BILGE_SWITCH, INPUT_PULLUP); 90 91 delay(10000); //give a chance to reprogram 92 93 // Set up a watchdog timer, long to allow communications with thinger, which take more than 16 seconds, but sometimes do hang and need a reset 94 //WatchDoggy.setup(WDT_SOFTCYCLE16M); // initialize WDT-softcounter refesh cycle on 16 minutes interval 95 96 DEBUG_PRINTLN("Setup Complete."); 97} 98 99void loop() { 100 101 DEBUG_PRINTLN("Entering main loop, starting thinger.handle."); 102 digitalWrite(LED_BUILTIN, LOW); // turn LED back off when returning to loop 103 104 digitalWrite(LED_BUILTIN, HIGH); // LED comes on for thinger.handle 105 // Clear the watchdog timer 106 //WatchDoggy.clear(); 107 thing.handle(); // LED is on 7-8 seconds, then off for ~15 seconds for the rest of the loop 108 //WatchDoggy.clear(); // Clear the watchdog timer 109 digitalWrite(LED_BUILTIN, LOW); // LED comes off when finished with thinger.handle 110 DEBUG_PRINTLN("thinger.handle done."); 111 112 113 // these declarations are not needed for DHT or thinger, but I'm 114 // them to get integers and avoid using overly precise data 115 byte humidity = dht.readHumidity(); 116 int8_t fahrenheit = dht.readTemperature(true); 117 118 byte bilge_depth = get_bilge_depth(); 119 120 // check for high water, call endpoint to send email if detected (call once 121 if ((digitalRead(highBilge) == LOW 122 || digitalRead(lowBilge) == LOW 123 || digitalRead(engineRoom) == LOW 124 || bilge_depth > 20) 125 && endpointRateLimiter) { 126 digitalWrite(LED_BUILTIN, HIGH); //LED comes on when water detected 127 DEBUG_PRINTLN("water sensor check positive!"); 128 pson data; 129 data["water high bilge"] = digitalRead(highBilge); 130 data["water low bilge"] = digitalRead(lowBilge); 131 data["water engine room"] = digitalRead(engineRoom); 132 data["bilge water depth"] = bilge_depth; 133 thing.call_endpoint("WaterDetectedEmail", data); 134 endpointRateLimiter = 0; 135 } 136 else {digitalWrite(LED_BUILTIN, LOW); 137 DEBUG_PRINTLN("water sensor check clear.");} 138 139 // bilge pump run timer 140 /* static unsigned long bilge_timer = millis(); 141 static unsigned long bilgeTimeHigh = 0; //[seconds] 142 // check bilge pump 143 if (diintgitalRead(BILGE_SWITCH) == LOW) // Bilge switch activated by high water 144 { 145 if (millis() - bilge_timer > 1000) // Count every second water is high 146 { bilge_timer = millis(); 147 bilgeTimeHigh++; } 148 } 149 else {bilge_timer = millis();} 150 */ 151 152 pson data; 153 //data["bilge pump time"] = bilgeTimeHigh; 154 data["humidity"] = humidity; 155 //data["celsius"] = celsius; 156 data["fahrenheit"] = fahrenheit; 157 data["water high bilge"] = digitalRead(highBilge); 158 data["water low bilge"] = digitalRead(lowBilge); 159 data["water engine room"] = digitalRead(engineRoom); 160 data["bilge water depth"] = bilge_depth; 161 162 // Print the data to the Serial monitor when debugging 163 DEBUG_PRINTLN("about to write data to thinger bucket"); 164 //DEBUG_PRINT("Current:"); 165 //DEBUG_PRINTLN(Current); 166 //DEBUG_PRINT("Voltage:"); 167 //DEBUG_PRINTLN(Voltage); 168 //DEBUG_PRINT("SOC:"); 169 //DEBUG_PRINTLN(SOC); 170 DEBUG_PRINT("Humidity:"); 171 DEBUG_PRINTLN(humidity); 172 DEBUG_PRINT("Temperature (F):"); 173 DEBUG_PRINTLN(fahrenheit); 174 DEBUG_PRINT("Water in bilge (cm):"); 175 DEBUG_PRINTLN(bilge_depth); 176 177 thing.write_bucket("BoatMonitorDataBucket", data); //died here a couple times 178 DEBUG_PRINTLN("Wrote data to thinger bucket, now to sleep!"); 179 180 // Sleep 181 // Shut stuff off // test the power savings of these and uncomment or remove them 182 // USBDevice.detach(); // Is this just communcations? What is power is coming in through USB? 183 /* Serial.end(); 184 Serial1.end(); 185 digitalWrite(LED_BUILTIN, LOW); 186 */ 187 thing.stop(); //this seems to prevent thinger.handle hanging. https://community.thinger.io/t/problem-with-gsm-900a/1874 188 //sleep for this many minutes (minutes * milliseconds in a minute) 189 LowPower.sleep(sleep_minutes * 60000); 190 191 // Turn stuff back on 192 // USBDevice.attach(); // remove this when finished testing to save a little power? 193 /*Serial.begin(115200); 194 Serial1.begin(19200); 195 */ 196 DEBUG_PRINTLN("Woke up!"); 197} 198 199// Ultrasonic proxmity sensor function 200//int8_t 201byte get_bilge_depth() { 202 // I considered a DHT provide the temp and RH in the bilge. While it wouldn't change quickly, it would change with lake temp over the summer 203 // and drastically when hauled out - but that would only cause a ~2cm difference in the result so I'll save the pins and complication 204 float celsius = 18; // dht.readTemperature(); 205 float humidity = 75; //dht.readHumidity(); 206 float sound_speed = (331.4 + (0.606 * celsius) + (0.0124* humidity))/10000; // speed of sound in cm/ms adjusted for temperature and humidity 207 float duration = sonar.ping_median(measurements_to_average, MAX_DISTANCE); 208 byte distance = (duration / 2) * sound_speed; 209 byte bilge_depth = 74 - distance; // Sensor is mounted 74 cm above the bilge floor 210 return bilge_depth; 211} 212 213 214/* 215void InterruptWake() // Interrupt routine, not currently called by the interrupts 216{ 217 digitalWrite(LED_BUILTIN, HIGH); //turn on the LED when woken. Can remove all the LED 218 // parts of the RTC/Sleep system when the sketch is done to save that power, or no leave 219 // it for confirming operation. But would I watch the LED for 20 minutes to see if it lights? 220 221 //Keep Interrupt routine short, but this is an alarm. Either trigger it here or in Thinger 222}*/ 223 224/* 225void dummy() { 226 // This function will be called once on device wakeup 227 boolean endpointRateLimiter = 1; // The copy of this at the top means one email per cold start, this one means one per wake 228 // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context 229} 230*/ 231 232/* 233void myshutdown() 234{ 235 could put something here that runs before the watchdog reset 236}*/
1 Arudino sketch for remote monitoring with Thinger.io: Victron BMV code, no ultrasonic
arduino
This version has code for my old Victron BMV-600, which I no longer use. The newer code lacks this, and has code for an ultrasonic sensor for measuring bilge depth. In the new code, I also addedd thing.stop() which appears to have drastically reduced how often the device hangs.
1// library name // for... 2#include "arduino_secrets.h" // private credentials 3#include <MKRGSM.h> // GSM communication, from Arduino 4#include <ThingerMKRGSM.h> // thinger.io, from thinger.io 5#include <DHT.h> // temperature sensor, from Adafruit 6#include <ArduinoLowPower.h> // sleep, from Arduino 7#include <SPI.h> // reading battery monitor over TTL/serial 8 9#define GPRS_APN "h2g2" // Get onto Google Fi network 10 11// Thinger.io credentials 12#define USERNAME "SECRET_THINGER_USERNAME" 13#define DEVICE_ID "SECRET_THINGER_DEVICE_ID" 14#define DEVICE_CREDENTIAL "SECRET_THINGER_DEVICE_CREDENTIAL" 15ThingerMKRGSM thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); 16 17// DHT config 18#define DHTPIN 2 // digital pin sensor is connected to 19#define DHTTYPE DHT22 // which DHT sensor? 11 or 22? 20DHT dht(DHTPIN, DHTTYPE); 21 22// Water sensors 23#define highBilge 5 // digital pin the sensor is connected to 24#define lowBilge 7 // digital pin the sensor is connected to 25#define engineRoom 8 // digital pin the sensor is connected to 26 27// Setting up Victron battery monitor variables 28char p_buffer[80]; 29#define P(str) (strcpy_P(p_buffer, PSTR(str)), p_buffer) 30 31char c; 32String V_buffer; 33 34float Current; 35float Voltage; 36float SOC; 37float TTG; 38float CE; 39int Alarm_low_voltage; 40int Alarm_high_voltage; 41int Alarm_low_soc; 42String Alarm; 43String Relay; 44 45boolean endpointRateLimiter = 1; 46 47void setup() { 48 Serial.begin(115200); 49 Serial.println("Starting setup"); 50 51 // Victron Battery Monitor 52 // DO NOT CONNECT POWER OR GROUND WIRES, the BMV is not isolated, 53 // the official Victron cable is isolating for this reason 54 // The Victron uses 3.3V TTL, so the MKR boards 3.3V circuit is perfect 55 56 // initialize serial communication with the Victron BMV at 19200 bits per second (per jepefe): 57 // Serial1 is a hardware serial port in pins 13 and 14 in the MKR series 58 Serial1.begin(19200); // In jepefe's code, for Arduinos without hardware serial, this would be Victron.begin(19200) 59 // and Victron was defined above by its pins and SoftwareSerial. Apparently it has been deprecated in favor of NewSoftSerial 60 // this website has plain and direct language about this, which is rarely discussed in discussions I have seen about 61 // downstream use of the serials. https://www.pjrc.com/teensy/td_libs_SoftwareSerial.html 62 63 thing.set_apn(GPRS_APN); 64 65 // set builtin led to output and turn it off 66 pinMode(LED_BUILTIN, OUTPUT); 67 digitalWrite(LED_BUILTIN, LOW); 68 69 // Thinger.io resources 70 thing["led"] << [](pson & in) { 71 digitalWrite(LED_BUILTIN, in ? HIGH : LOW); 72 }; 73 74 // pin control example over internet (i.e. turning on/off a light, a relay, etc) 75 //thing["relay"] << digitalPin(7); //change this to the right pin when connecting the relay 76 77 //Temperature and RH sensor setup 78 dht.begin(); 79 80 // Wake on water detected 81 LowPower.attachInterruptWakeup(highBilge, NULL, LOW); 82 LowPower.attachInterruptWakeup(engineRoom, NULL, LOW); 83 LowPower.attachInterruptWakeup(lowBilge, NULL, LOW); 84 85 delay(15000); //give a chance to reprogram 86 Serial.println("end of setup"); 87} 88 89void loop() { 90 91 digitalWrite(LED_BUILTIN, LOW); // turn LED back off when returning to loop 92 93 thing.handle(); 94 Serial.println("thing.handle"); 95 96 // check for high water, call endpoint to send email if detected (call once) 97 if ((digitalRead(highBilge) == LOW 98 || digitalRead(lowBilge) == LOW 99 || digitalRead(engineRoom) == LOW) 100 && endpointRateLimiter) { 101 digitalWrite(LED_BUILTIN, HIGH); 102 pson data; 103 data["water high bilge"] = digitalRead(highBilge); 104 data["water low bilge"] = digitalRead(lowBilge); 105 data["water engine room"] = digitalRead(engineRoom); 106 thing.call_endpoint("WaterDetectedEmail", data); 107 endpointRateLimiter = 0; 108 } 109 else digitalWrite(LED_BUILTIN, LOW); 110 111 // these declarations are not needed for DHT or thinger, but I'm 112 // using them to get integers and avoid using overly precise data 113 int humidity = dht.readHumidity(); 114 //int celsius = dht.readTemperature(); 115 int fahrenheit = dht.readTemperature(true); 116 117 // Victron BMV code from: http://www.jw5zla.com/?p=7 (adapted for the MKR's hardware Serial1 (at pins 13,14) which most Arduinos lack) 118 if (Serial1.available()) { 119 c = Serial1.read(); 120 121 Serial.println(c); 122 123 if (V_buffer.length() <80) { 124 V_buffer += c; 125 } 126 127 if (c == '\n') { 128 129 if (V_buffer.startsWith("I")) { 130 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 131 double temp_int = temp_string.toInt(); 132 Current = (float) temp_int/1000; 133 } 134 135 if (V_buffer.startsWith("V")) { 136 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 137 int temp_int = temp_string.toInt(); 138 Voltage = (float) temp_int/1000; 139 } 140 141 if (V_buffer.startsWith("SOC")) { 142 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 143 int temp_int = temp_string.toInt(); 144 SOC = (float) temp_int/10; 145 } 146 147 if (V_buffer.startsWith("TTG")) { 148 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 149 double temp_int = temp_string.toInt(); 150 if (temp_int >0) { 151 TTG = (float) temp_int/60; 152 } 153 else { 154 TTG = 240; 155 } 156 } 157 158 if (V_buffer.startsWith("CE")) { 159 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 160 double temp_int = temp_string.toInt(); 161 CE = (float) temp_int/1000; 162 } 163 164 if (V_buffer.startsWith("Alarm")) { 165 Alarm = V_buffer.substring(V_buffer.indexOf("\ ")+1); 166 Alarm.trim(); 167 } 168 169 if (V_buffer.startsWith("Relay")) { 170 Relay = V_buffer.substring(V_buffer.indexOf("\ ")+1); 171 Relay.trim(); 172 } 173 174 if (V_buffer.startsWith("AR")) { 175 String temp_string = V_buffer.substring(V_buffer.indexOf("\ ")+1); 176 int temp_int = temp_string.toInt(); 177 178 if (bitRead(temp_int,0)) { 179 Alarm_low_voltage = 1; 180 } 181 else { 182 Alarm_low_voltage = 0; 183 } 184 185 if (bitRead(temp_int,1)) { 186 Alarm_high_voltage = 1; 187 } 188 else { 189 Alarm_high_voltage = 0; 190 } 191 192 if (bitRead(temp_int,2)) { 193 Alarm_low_soc = 1; 194 } 195 else { 196 Alarm_low_soc = 0; 197 } 198 } 199 Serial.println(Current); 200 Serial.println(Voltage); 201 Serial.println(SOC); 202 V_buffer=""; 203 } // end if new line 204 } // end if Serial1 (Victron) is available 205 206 pson data; 207 data["BMV:Current"] = Current; 208 data["BMV:Voltage"] = Voltage; 209 data["BMV:SoC"] = SOC; 210 //data["BMV:TTG"] = TTG; 211 //data["BMV:CE"] = CE; 212 //data["BMV:int Alarm_low_voltage; 213 //data["BMV:int Alarm_high_voltage; 214 //data["BMV:int Alarm_low_soc; 215 //data["BMV:Alarm"] = Alarm; 216 //data["BMV:Relay"] = Relay; 217 218 data["humidity"] = humidity; 219 //data["celsius"] = celsius; 220 data["fahrenheit"] = fahrenheit; 221 data["water high bilge"] = digitalRead(highBilge); 222 data["water low bilge"] = digitalRead(lowBilge); 223 data["water engine room"] = digitalRead(engineRoom); 224 thing.write_bucket("BoatMonitorDataBucket", data); 225 Serial.println("wrote data to thinger bucket, now to sleep!"); 226 227 //sleep for this many minutes (minutes*milliseconds in a minute) 228 LowPower.sleep(2 * 60000); // 2 for testing, 15 for summer, 30 for winter 229} 230/* 231void InterruptWake() // Interrupt routine, not currently called by the interrupts 232{ 233 digitalWrite(LED_BUILTIN, HIGH); //turn on the LED when woken. Can remove all the LED 234 // parts of the RTC/Sleep system when the sketch is done to save that power, or no leave 235 // it for confirming operation. But would I watch the LED for 20 minutes to see if it lights? 236 237 //Keep Interrupt routein short, but this is an alarm. Either trigger it here or in Thinger 238}*/
Downloadable files
Wiring schematic
This is my first fritzing sketch; recommendations are welcome. These are not the right water sensors (these are analog, but I show them as if they were digital like the ones I'm using are). I didn't find a good way to depict the connections to the battery monitor and charge controller. Also the battery is actually connected to the JST port on the Arduino, not wired directly to pins.
Wiring schematic
Wiring schematic
This is my first fritzing sketch; recommendations are welcome. These are not the right water sensors (these are analog, but I show them as if they were digital like the ones I'm using are). I didn't find a good way to depict the connections to the battery monitor and charge controller. Also the battery is actually connected to the JST port on the Arduino, not wired directly to pins.
Wiring schematic
Comments
Only logged in users can leave comments
damonlane
0 Followers
•0 Projects
Table of contents
Intro
31
0