Example showing all possible functionality
-
Walking Through the Code
- Defines and Includes
- Logger Settings
-
Wifi/Cellular Modem Options
- Digi XBee Cellular - Transparent Mode
- Digi XBee3 LTE-M - Bypass Mode
- Digi XBee 3G - Bypass Mode
- Digi XBee S6B Wifi
- Espressif ESP8266
- Quectel BG96
- Sequans Monarch
- SIMCom SIM800
- SIMCom SIM7000
- SIMCom SIM7080G (EnviroDIY LTE Bee])
- Sodaq GPRSBee
- u-blox SARA R410M
- u-blox SARA U201
- Modem Measured Variables
-
Sensors and Measured Variables
- The processor as a sensor
- Maxim DS3231 RTC as a sensor
- Alphasense CO2
- AOSong AM2315
- AOSong DHT
- Apogee SQ-212 Quantum Light Sensor
- Atlas Scientific EZO Circuits
- Bosch BME280 Environmental Sensor
- Bosch BMP388 and BMP398 Pressure Sensors
- Campbell OBS3+ Analog Turbidity Sensor
- Decagon ES2 Conductivity and Temperature Sensor
- External Voltage via TI ADS1x15
- Freescale Semiconductor MPL115A2 Miniature I2C Digital Barometer
- GroPoint Profile GPLP-8 Eight-Segment Soil Moisture and Temperature Profiling Probe
- Keller RS485/Modbus Water Level Sensors
- Maxbotix HRXL Ultrasonic Range Finder
- Maxim DS18 One Wire Temperature Sensor
- Measurement Specialties MS5803-14BA Pressure Sensor
- Meter SDI-12 Sensors
- PaleoTerra Redox Sensors
- Trinket-Based Tipping Bucket Rain Gauge
- Northern Widget Tally Event Counter
- TI INA219 High Side Current Sensor
- Turner Cyclops-7F Submersible Fluorometer
- Turner Turbidity Plus with Integrated Wiper
- Analog Electrical Conductivity using the Processor's Analog Pins
-
Yosemitech RS485/Modbus Environmental Sensors
- Yosemitech Y504 Dissolved Oxygen Sensor
- Yosemitech Y510 Turbidity Sensor
- Yosemitech Y511 Turbidity Sensor with Wiper
- Yosemitech Y513 Blue-Green Algae Sensor
- Yosemitech Y514 Chlorophyll Sensor
- Yosemitech Y520 Conductivity Sensor
- Yosemitech Y532 pH Sensor
- Yosemitech Y533 Oxidation Reduction Potential (ORP) Sensor
- Yosemitech Y551 Carbon Oxygen Demand (COD) Sensor with Wiper
- Yosemitech Y560 Ammonium Sensor
- Yosemitech Y700 Pressure Sensor
- Yosemitech Y4000 Multi-Parameter Sonde
- Zebra Tech D-Opto Dissolved Oxygen Sensor
- Calculated Variables
- Creating the array, logger, publishers
- Extra Working Functions
- Arduino Setup Function
- Arduino Loop Function
- PlatformIO Configuration
- The Complete Code
This shows most of the functionality of the library at once. It has code in it for every possible sensor and modem and for both AVR and SAMD boards. This example should never be used directly; it is intended to document all possibilities and to verify compilating.
To create your own code, I recommend starting from a much simpler targeted example, like the Logging to MMW example, and then adding to it based on only the parts of this menu example that apply to you.
Walking Through the Code
Defines and Includes
Defines for the Arduino IDE
The top few lines of the examples set defines of buffer sizes and yields needed for the Arduino IDE. That IDE read any defines within the top few lines and applies them as build flags for the processor. This is not standard behavior for C++ (which is what Arduino code really is) - this is a unique aspect of the Arduino IDE.
If you are using PlatformIO, you should instead set these as global build flags in your platformio.ini. This is standard behaviour for C++.
Library Includes
Next, include the libraries needed for every program using ModularSensors.
Logger Settings
Creating Extra Serial Ports
This section of the example has all the code to create and link to serial ports for both AVR and SAMD based boards. The EnviroDIY Mayfly, the Arduino Mega, UNO, and Leonardo are all AVR boards. The Arduino Zero, the M0 and the Sodaq Autonomo are all SAMD boards.
Many different sensors communicate using some sort of serial or transistor-transistor-logic (TTL) protocol. Among these are any sensors using RS232, RS485, RS422. Generally each serial variant (or sometimes each sensor) needs a dedicated serial "port" - its own connection to the processor. Most processors have built in dedicated wires for serial communication - "Hardware" serial. See the page on Arduino streams for much more detail about serial connections with Arduino processors.
AVR Boards
Most Arduino AVR style boards have very few (ie, one, or none) dedicated serial ports available after counting out the programming serial port. So to connect anything else, we need to try to emulate the processor serial functionality with a software library. This example shows three possible libraries that can be used to emulate a serial port on an AVR board.
AltSoftSerial
AltSoftSerial by Paul Stoffregen is the most accurate software serial port for AVR boards. AltSoftSerial can only be used on one set of pins on each board so only one AltSoftSerial port can be used. Not all AVR boards are supported by AltSoftSerial. See the processor compatibility page for more information on which pins are used on supported boards.
NeoSWSerial
NeoSWSerial is the best software serial that can be used on any pin supporting interrupts. You can use as many instances of NeoSWSerial as you want. Each instance requires two pins, one for data in and another for data out. If you only want to use the serial line for incoming or outgoing data, set the other pin to -1. Not all AVR boards are supported by NeoSWSerial.
When using NeoSWSerial we will also have to actually set the data receiving (Rx) pin modes for interrupt in the setup function.
SoftwareSerial with External Interrupts
The "standard" software serial library uses interrupts that conflict with several other libraries used within this program. I've created a version of software serial that has been stripped of interrupts but it is still far from ideal. This should be used only use if necessary. It is not a very accurate serial port!
Accepting its poor quality, you can use as many instances of SoftwareSerial as you want. Each instance requires two pins, one for data in and another for data out. If you only want to use the serial line for incoming or outgoing data, set the other pin to -1.
When using SoftwareSerial with External Interrupts we will also have to actually set the data receiving (Rx) pin modes for interrupt in the setup function.
Software I2C/Wire
This creates a software I2C (wire) instance that can be shared between multiple sensors. Only Testato's SoftwareWire library is supported.
SAMD Boards
The SAMD21 supports up to 6 hardware serial ports, which is awesome. But, the Arduino core doesn't make use of all of them, so we have to assign them ourselves.
This section of code assigns SERCOM's 1 and 2 to act as Serial2 and Serial3 on pins 10/11 and 5/2 respectively. These pin selections are based on the Adafruit Feather M0.
In addition to creating the extra SERCOM ports here, the pins must be set up as the proper pin peripherals after the serial ports are begun. This is shown in the SAMD Pin Peripherals section of the setup function.
NOTE: The SAMD51 board has an amazing 8 available SERCOM's, but I do not have any exmple code for using them.
Assigning Serial Port Functionality
This section just assigns all the serial ports from the Creating Extra Serial Ports section above to specific functionality. For a board with the option of up to 4 hardware serial ports, like the SAMD21 or Arduino Mega, we use the Serial1 to talk to the modem, Serial2 for modbus, and Serial3 for the Maxbotix.
For an AVR board where we're relying on a mix of hardware and software ports, we use hardware Serial 1 for the modem, AltSoftSerial for modbus, and NeoSWSerial for the Maxbotix. Depending on how you rank the importance of each component, you can adjust these to your liking.
Logging Options
Here we set options for the logging and dataLogger object. This includes setting the time zone (daylight savings time is NOT applied) and setting all of the input and output pins related to the logger.
Wifi/Cellular Modem Options
This modem section is very lengthy because it contains the code with the constructor for every possible supported modem module. Do NOT try to use more than one modem at a time - it will NOT work.
To create any of the modems, we follow a similar pattern:
First, we'll create a pointer to the serial port (Arduino Stream object) that we'll use for communication between the modem and the MCU. We also assign the baud rate to a variable here. There is a table of Default baud rates of supported modules on the Notes about Modems page. The baud rate of any of the modules can be changed using AT commands or the modem.gsmModem.setBaud(uint32_t baud)
function.
Next, we'll assign all the pin numbers for all the other pins connected between the modem and the MCU. Pins that do not apply should be set as -1. There is a table of general Sleep and Reset Pin Labels and Pin Numbers to Use when Connecting to a Mayfly 0.x on the Notes about Modems page.
All the modems also need some sort of network credentials for internet access. For WiFi modems, you need the network name and password (assuming WPA2). For cellular models, you will need the APN assigned to you by the carrier you bought your SIM card from.
Digi XBee Cellular - Transparent Mode
This is the code to use for any of Digi's cellular XBee or XBee3 modules. All of them can be implented as a DigiXBeeCellularTransparent object - a subclass of DigiXBee and loggerModem. To create a DigiXBeeCellularTransparent object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the status pin,
- whether the status pin is the true status pin (
ON/SLEEP_N/DIO9
) or theCTS_N/DIO7
pin, - the MCU pin connected to the
RESET_N
pin, - the
DTR_N/SLEEP_RQ/DIO8
pin, - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the EnviroDIY Mayfly is available on the Modem Notes page.
Depending on your cellular carrier, it is best to select the proper carrier profile and network. Setting these helps the modem to connect to network faster. This is shows in the XBee Cellular Carrier chunk of the setup function.
Digi XBee3 LTE-M - Bypass Mode
This code is for Digi's LTE-M XBee3 based on the u-blox SARA R410M - used in bypass mode. To create a DigiXBeeLTEBypass object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the status pin,
- whether the status pin is the true status pin (
ON/SLEEP_N/DIO9
) or theCTS_N/DIO7
pin, - the MCU pin connected to the
RESET_N
pin, - the
DTR_N/SLEEP_RQ/DIO8
pin, - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the EnviroDIY Mayfly is available on the Modem Notes page.
Depending on your cellular carrier, it is best to select the proper carrier profile and network. Setting these helps the modem to connect to network faster. This is shows in the SARA R4 Cellular Carrier chunk of the setup function.
Digi XBee 3G - Bypass Mode
This code is for Digi's 3G/2G XBee based on the u-blox SARA U201 - used in bypass mode. To create a DigiXBee3GBypass object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the status pin,
- whether the status pin is the "true" status pin (
ON/SLEEP_N/DIO9
) or theCTS_N/DIO7
pin, - the MCU pin connected to the
RESET_N
pin, - the
DTR_N/SLEEP_RQ/DIO8
pin, - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the EnviroDIY Mayfly is available on the Modem Notes page.
Digi XBee S6B Wifi
This code is for the Digi's S6B wifi module. To create a DigiXBeeWifi object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the status pin,
- whether the status pin is the "true" status pin (
ON/SLEEP_N/DIO9
) or theCTS_N/DIO7
pin, - the MCU pin connected to the
RESET_N
pin, - the
DTR_N/SLEEP_RQ/DIO8
pin, - the wifi access point name,
- and the wifi WPA2 password.
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the EnviroDIY Mayfly is available on the Modem Notes page.
Espressif ESP8266
This code is for the Espressif ESP8266 or ESP32 operating with "AT" firmware. To create a EspressifESP8266 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the reset pin (MCU pin connected to the ESP's
RSTB/DIO16
), - the wifi access point name,
- and the wifi WPA2 password.
Pins that do not apply should be set as -1.
Because the ESP8266's default baud rate is too fast for an 8MHz board like the Mayfly, to use it you need to drop the baud rate down for sucessful communication. You can set the slower baud rate using some external method, or useing the code from the ESP8266 Baud Rate(https://envirodiy.github.io/ModularSensors/menu_
Quectel BG96
This code is for the Dragino, Nimbelink or other boards based on the Quectel BG96. To create a QuectelBG96 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
STATUS
pin, - the MCU pin connected to the
RESET_N
pin, - the MCU pin connected to the
PWRKEY
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1.
If you are interfacing with a Nimbelink Skywire board via the Skywire development board, you also need to handle the fact that the development board reverses the levels of the status, wake, and reset pins. Code to invert the pin levels is in the Skywire Pin Inversions part of the setup function below.
Sequans Monarch
This code is for the Nimbelink LTE-M Verizon/Sequans or other boards based on the Sequans Monarch series SoC. To create a SequansMonarch object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to either the
GPIO3/STATUS_LED
orPOWER_MON
pin, - the MCU pin connected to the
RESETN
pin, - the MCU pin connected to the
RTS
orRTS0
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1.
If you are interfacing with a Nimbelink Skywire board via the Skywire development board, you also need to handle the fact that the development board reverses the levels of the status, wake, and reset pins. Code to invert the pin levels is in the Skywire Pin Inversions part of the setup function below.
The default baud rate of the SVZM20 is much too fast for almost all Arduino boards. Before attampting to connect a SVZM20 to an Arduino you should connect it to your computer and use AT commands to decrease the baud rate. The proper command to decrease the baud rate to 9600 (8N1) is: AT+IPR=9600
.
SIMCom SIM800
This code is for a SIMCom SIM800 or SIM900 or one of their many variants, including the Adafruit Fona and the Sodaq 2GBee R4. To create a SIMComSIM800 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
STATUS
pin, - the MCU pin connected to the
RESET
pin, - the MCU pin connected to the
PWRKEY
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1.
NOTE: This is NOT the correct form for a Sodaq 2GBee R6 or R7. See the section for a 2GBee R6.
SIMCom SIM7000
This code is for a SIMCom SIM7000 or one of its variants. To create a SIMComSIM7000 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
STATUS
pin, - the MCU pin connected to the
RESET
pin, - the MCU pin connected to the
PWRKEY
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1.
SIMCom SIM7080G (EnviroDIY LTE Bee])
This code is for a SIMCom SIM7080G or one of its variants, including the EnviroDIY LTE Bee.
To create a SIMComSIM7080 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
STATUS
pin, - the MCU pin connected to the
PWRKEY
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the EnviroDIY LTE Bee and the EnviroDIY Mayfly is available on the Modem Notes page.
Sodaq GPRSBee
This code is for the Sodaq 2GBee R6 and R7 based on the SIMCom SIM800. To create a Sodaq2GBeeR6 object we need to know
- the serial object name,
- the MCU pin controlling modem power, (NOTE: On the GPRSBee R6 and R7 the pin labeled as ON/OFF in Sodaq's diagrams is tied to both the SIM800 power supply and the (inverted) SIM800
PWRKEY
. You should enter this pin as the power pin.) - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. The GPRSBee R6/R7 does not expose the RESET
pin of the SIM800. The PWRKEY
is held LOW
as long as the SIM800 is powered (as mentioned above). A helpful table detailing the pins to use with the Sodaq GPRSBee and the EnviroDIY Mayfly is available on the Modem Notes page.
u-blox SARA R410M
This code is for modules based on the 4G LTE-M u-blox SARA R410M including the Sodaq UBee. To create a SodaqUBeeR410M object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
V_INT
pin (for status), - the MCU pin connected to the
RESET_N
pin, - the MCU pin connected to the
PWR_ON
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the UBee R410M and the EnviroDIY Mayfly is available on the Modem Notes page.
Depending on your cellular carrier, it is best to select the proper carrier profile and network. Setting these helps the modem to connect to network faster. This is shows in the SARA R4 Cellular Carrier chunk of the setup function.
u-blox SARA U201
This code is for modules based on the 3G/2G u-blox SARA U201 including the Sodaq UBee or the Sodaq 3GBee. To create a SodaqUBeeU201 object we need to know
- the serial object name,
- the MCU pin controlling modem power,
- the MCU pin connected to the
V_INT
pin (for status), - the MCU pin connected to the
RESET_N
pin, - the MCU pin connected to the
PWR_ON
pin (for sleep request), - and the SIM card's cellular access point name (APN).
Pins that do not apply should be set as -1. A helpful table detailing the pins to use with the Sodaq UBee U201 and the EnviroDIY Mayfly is available on the Modem Notes page.
Modem Measured Variables
After creating the modem object, we can create Variable objects for each of the variables the modem is capable of measuring (Modem_
Sensors and Measured Variables
The processor as a sensor
Set options and create the objects for using the processor as a sensor to report battery level, processor free ram, and sample number.
The processor can return the number of "samples" it has taken, the amount of RAM it has available and, for some boards, the battery voltage (EnviroDIY Mayfly, Sodaq Mbili, Ndogo, Autonomo, and One, Adafruit Feathers). The version of the board is required as input (ie, for a EnviroDIY Mayfly: "v0.3" or "v0.4" or "v0.5"). Use a blank value (ie, "") for un-versioned boards. Please note that while you can opt to average more than one sample, it really makes no sense to do so for the processor. The number of "samples" taken will increase by one for each time another processor "measurement" is taken so averaging multiple measurements from the processor will result in the number of samples increasing by more than one with each loop.
Maxim DS3231 RTC as a sensor
In addition to the time, we can also use the required DS3231 real time clock to report the temperature of the circuit board. This temperature is not equivalent to an environmental temperature measurement and should only be used to as a diagnostic. As above, we create both the sensor and the variables measured by it.
Alphasense CO2
AOSong AM2315
Here is the code for the AOSong AM2315 temperature and humidity sensor. This is an I2C sensor with only one possible address so the only argument required for the constructor is the pin on the MCU controlling power to the AM2315 (AM2315Power). The number of readings to average from the sensor is optional, but can be supplied as the second argument for the constructor if desired.
AOSong DHT
Here is the code for the AOSong DHT temperature and humidity sensor. To create the DHT Sensor we need the power pin, the data pin, and the DHT type. The number of readings to average from the sensor is optional, but can be supplied as the fourth argument for the constructor if desired.
Apogee SQ-212 Quantum Light Sensor
Here is the code for the Apogee SQ-212 Quantum Light Sensor. The SQ-212 is not directly connected to the MCU, but rather to an TI ADS1115 that communicates with the MCU. The Arduino pin controlling power on/off and the analog data channel on the TI ADS1115 are required for the sensor constructor. If your ADD converter is not at the standard address of 0x48, you can enter its actual address as the third argument. The number of readings to average from the sensor is optional, but can be supplied as the fourth argument for the constructor if desired.
Atlas Scientific EZO Circuits
The next several sections are for Atlas Scientific EZO circuts and sensors. The sensor class constructors for each are nearly identical, except for the class name. In the most common setup, with hardware I2C, the only required argument for the constructor is the Arduino pin controlling power on/off; the i2cAddressHex is optional as is the number of readings to average.
The default I2C addresses for the circuits are:
- CO2: 0x69 (105)
- DO: 0x61 (97)
- EC (conductivity): 0x64 (100)
- ORP (redox): 0x62 (98)
- pH: 0x63 (99)
- RTD (temperature): 0x66 (102) All of the circuits can be re-addressed to any other 8 bit number if desired. To use multiple circuits of the same type, re-address them.
Atlas Scientific EZO-CO2 Embedded NDIR Carbon Dioxide Sensor
Atlas Scientific EZO-DO Dissolved Oxygen Sensor
Atlas Scientific EZO-ORP Oxidation/Reduction Potential Sensor
Atlas Scientific EZO-pH Sensor
Atlas Scientific EZO-RTD Temperature Sensor
Atlas Scientific EZO-EC Conductivity Sensor
Bosch BME280 Environmental Sensor
Here is the code for the Bosch BME280 environmental sensor. The only input needed is the Arduino pin controlling power on/off; the i2cAddressHex is optional as is the number of readings to average. Keep in mind that the possible I2C addresses of the BME280 match those of the MS5803; when using those sensors together, make sure they are set to opposite addresses.
Bosch BMP388 and BMP398 Pressure Sensors
Campbell ClariVUE SDI-12 Turbidity Sensor
Campbell OBS3+ Analog Turbidity Sensor
This is the code for the Campbell OBS3+. The Arduino pin controlling power on/off, analog data channel on the TI ADS1115, and calibration values in Volts for Ax^2 + Bx + C are required for the sensor constructor. A custom variable code can be entered as a second argument in the variable constructors, and it is very strongly recommended that you use this otherwise it will be very difficult to determine which return is high and which is low range on the sensor. If your ADD converter is not at the standard address of 0x48, you can enter its actual address as the third argument. Do NOT forget that if you want to give a number of measurements to average, that comes after the i2c address in the constructor!
Note that to access both the high and low range returns, two instances must be created, one at the low range return pin and one at the high pin.
Campbell RainVUE SDI-12 Precipitation Sensor
Decagon CTD-10 Conductivity, Temperature, and Depth Sensor
Decagon ES2 Conductivity and Temperature Sensor
The SDI-12 address of the sensor, the Arduino pin controlling power on/off, and the Arduino pin sending and receiving data are required for the sensor constructor. Optionally, you can include a number of distinct readings to average. The data pin must be a pin that supports pin-change interrupts.
Everlight ALS-PT19 Ambient Light Sensor
External Voltage via TI ADS1x15
The Arduino pin controlling power on/off and the analog data channel on the TI ADS1115 are required for the sensor constructor. If using a voltage divider to increase the measurable voltage range, enter the gain multiplier as the third argument. If your ADD converter is not at the standard address of 0x48, you can enter its actual address as the fourth argument. The number of measurements to average, if more than one is desired, goes as the fifth argument.
Freescale Semiconductor MPL115A2 Miniature I2C Digital Barometer
The only input needed for the sensor constructor is the Arduino pin controlling power on/off and optionally the number of readings to average. Because this sensor can have only one I2C address (0x60), it is only possible to connect one of these sensors to your system.
GroPoint Profile GPLP-8 Eight-Segment Soil Moisture and Temperature Profiling Probe
In-Situ Aqua/Level TROLL Pressure, Temperature, and Depth Sensor
In-Situ RDO PRO-X Rugged Dissolved Oxygen Probe
Keller RS485/Modbus Water Level Sensors
The next two sections are for Keller RS485/Modbus water level sensors. The sensor class constructors for each are nearly identical, except for the class name. The sensor constructors require as input: the sensor modbus address, a stream instance for data (ie, Serial
), and one or two power pins. The Arduino pin controlling the receive and data enable on your RS485-to-TTL adapter and the number of readings to average are optional. (Use -1 for the second power pin and -1 for the enable pin if these don't apply and you want to average more than one reading.) Please see the section "[Notes on Arduino Streams and Software Serial](https://envirodiy.github.io/ModularSensors/page_arduino_streams.html)" for more information about what streams can be used along with this library. In tests on these sensors, SoftwareSerial_ExtInts did not work to communicate with these sensors, because it isn't stable enough. AltSoftSerial and HardwareSerial work fine.
The serial ports for this example are created in the Creating Extra Serial Ports section and then assigned to modbus functionality in the Assigning Serial Port Functionality section.
Up to two power pins are provided so that the RS485 adapter, the sensor and/or an external power relay can be controlled separately. If the power to everything is controlled by the same pin, use -1 for the second power pin or omit the argument. If they are controlled by different pins and no other sensors are dependent on power from either pin then the order of the pins doesn't matter. If the RS485 adapter, sensor, or relay are controlled by different pins and any other sensors are controlled by the same pins you should put the shared pin first and the un-shared pin second. Both pins cannot be shared pins.
Keller Acculevel High Accuracy Submersible Level Transmitter
Keller Nanolevel Level Transmitter
Maxbotix HRXL Ultrasonic Range Finder
The Arduino pin controlling power on/off, a stream instance for received data (ie, Serial
), and the Arduino pin controlling the trigger are required for the sensor constructor. (Use -1 for the trigger pin if you do not have it connected.) Please see the section "[Notes on Arduino Streams and Software Serial](https://envirodiy.github.io/ModularSensors/page_arduino_streams.html)" for more information about what streams can be used along with this library.
The serial ports for this example are created in the Creating Extra Serial Ports section and then assigned to the sonar functionality in the Assigning Serial Port Functionality section.
Maxim DS18 One Wire Temperature Sensor
The OneWire hex address of the sensor, the Arduino pin controlling power on/off, and the Arduino pin sending and receiving data are required for the sensor constructor, though the address can be omitted if only one sensor is used. The OneWire address is an array of 8 hex values, for example: {0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0}. To get the address of your sensor, plug a single sensor into your device and run the oneWireSearch example or the Single example provided within the Dallas Temperature library. The sensor address is programmed at the factory and cannot be changed.
Measurement Specialties MS5803-14BA Pressure Sensor
The only input needed is the Arduino pin controlling power on/off; the i2cAddressHex and maximum pressure are optional as is the number of readings to average. Keep in mind that the possible I2C addresses of the MS5803 match those of the BME280.
Meter SDI-12 Sensors
The next few sections are for Meter SDI-12 sensors. The SDI-12 address of the sensor, the Arduino pin controlling power on/off, and the Arduino pin sending and receiving data are required for the sensor constructor. Optionally, you can include a number of distinct readings to average. The data pin must be a pin that supports pin-change interrupts.
Meter ECH2O Soil Moisture Sensor
Meter Hydros 21 Conductivity, Temperature, and Depth Sensor
Meter Teros 11 Soil Moisture Sensor
PaleoTerra Redox Sensors
Because older versions of these sensors all ship with the same I2C address, and more than one is frequently used at different soil depths in the same profile, this module has an optional dependence on Testato's SoftwareWire library for software I2C.
To use software I2C, compile with the build flag -D MS_PALEOTERRA_SOFTWAREWIRE
. See the software wire section for an example of creating a software I2C instance to share between sensors.
The constructors for the software I2C implementation requires either the SCL and SDA pin numbers or a reference to the I2C object as arguments. All variants of the constructor require the Arduino power pin. The I2C address can be given if it the sensor is not set to the default of 0x68. A number of readings to average can also be given.
Trinket-Based Tipping Bucket Rain Gauge
This is for use with a simple external I2C tipping bucket counter based on the Adafriut Trinket. All constructor arguments are optional, but the first argument is for the I2C address of the tip counter (if not 0x08) and the second is for the depth of rain (in mm) per tip event (if not 0.2mm). Most metric tipping buckets are calibrated to have 1 tip per 0.2mm of rain. Most English tipping buckets are calibrated to have 1 tip per 0.01" of rain, which is 0.254mm. Note that you cannot input a number of measurements to average because averaging does not make sense with this kind of counted variable.
Sensirion SHT4X Digital Humidity and Temperature Sensor
Northern Widget Tally Event Counter
This is for use with Northern Widget's Tally event counter
The only option for the constructor is an optional setting for the I2C address, if the counter is not set at the default of 0x33. The counter should be continuously powered.
TI INA219 High Side Current Sensor
This is the code for the TI INA219 high side current and voltage sensor. The Arduino pin controlling power on/off is all that is required for the constructor. If your INA219 is not at the standard address of 0x40, you can enter its actual address as the fourth argument. The number of measurements to average, if more than one is desired, goes as the fifth argument.
Turner Cyclops-7F Submersible Fluorometer
This is the code for the Turner Cyclops-7F submersible fluorometer. The Arduino pin controlling power on/off and all calibration information is needed for the constructor. The address of the ADS1x15, if it is different than the default of 0x48, can be entered after the calibration information. The number of measurements to average, if more than one is desired, is the last argument.
The Cyclops sensors are NOT pre-calibrated and must be calibrated prior to deployment.
Turner Turbidity Plus with Integrated Wiper
This is the code for the Turner Turbidity Plus analog turbidity sensor.
The Turbidity Plus sensors are NOT pre-calibrated and must be calibrated prior to deployment.
Analog Electrical Conductivity using the Processor's Analog Pins
This is the code for the measuring electrical conductivity using the processor's internal ADC and analog input pins. The Arduino pin controlling power on/off and the sensing pin are required for the constuctor. The power supply for the sensor absolutely must be switched on and off between readings! The resistance of your in-circuit resistor, the cell constant for your power cord, and the number of measurements to average are the optional third, fourth, and fifth arguments. If your processor has an ADS with resolution greater or less than 10-bit, compile with the build flag -D ANALOG_EC_ADC_RESOLUTION=##
. For best results, you should also connect the AREF pin of your processors ADC to the power supply for the and compile with the build flag -D ANALOG_EC_ADC_REFERENCE_MODE=EXTERNAL
.
VEGA VEGA PULS 21
Yosemitech RS485/Modbus Environmental Sensors
The next several sections are for Yosemitech brand sensors. The sensor class constructors for each are nearly identical, except for the class name. The sensor constructor requires as input: the sensor modbus address, a stream instance for data (ie, Serial
), and one or two power pins. The Arduino pin controlling the receive and data enable on your RS485-to-TTL adapter and the number of readings to average are optional. (Use -1 for the second power pin and -1 for the enable pin if these don't apply and you want to average more than one reading.) For most of the sensors, Yosemitech strongly recommends averaging multiple (in most cases 10) readings for each measurement. Please see the section "[Notes on Arduino Streams and Software Serial](https://envirodiy.github.io/ModularSensors/page_arduino_streams.html)" for more information about what streams can be used along with this library. In tests on these sensors, SoftwareSerial_ExtInts did not work to communicate with these sensors, because it isn't stable enough. AltSoftSerial and HardwareSerial work fine. NeoSWSerial is a bit hit or miss, but can be used in a pinch.
The serial ports for this example are created in the Creating Extra Serial Ports section and then assigned to modbus functionality in the Assigning Serial Port Functionality section.
Yosemitech Y504 Dissolved Oxygen Sensor
Yosemitech Y510 Turbidity Sensor
Yosemitech Y511 Turbidity Sensor with Wiper
Yosemitech Y513 Blue-Green Algae Sensor
Yosemitech Y514 Chlorophyll Sensor
Yosemitech Y520 Conductivity Sensor
Yosemitech Y532 pH Sensor
Yosemitech Y533 Oxidation Reduction Potential (ORP) Sensor
Yosemitech Y551 Carbon Oxygen Demand (COD) Sensor with Wiper
Yosemitech Y560 Ammonium Sensor
Yosemitech Y700 Pressure Sensor
Yosemitech Y4000 Multi-Parameter Sonde
Zebra Tech D-Opto Dissolved Oxygen Sensor
The SDI-12 address of the sensor, the Arduino pin controlling power on/off, and the Arduino pin sending and receiving data are required for the sensor constructor. Optionally, you can include a number of distinct readings to average. The data pin must be a pin that supports pin-change interrupts.
Calculated Variables
Create new Variable objects calculated from the measured variables. For these calculate variables, we must not only supply a function for the calculation, but also all of the metadata about the variable - like the name of the variable and its units.
Creating the array, logger, publishers
The variable array
Create a VariableArray containing all of the Variable objects that we are logging the values of.
This shows three differnt ways of creating the same variable array and filling it with variables. You should only use ONE of these in your own code
Creating Variables within an Array
Here we use the new
keyword to create multiple variables and get pointers to them all at the same time within the arry.
Creating Variables and Pasting UUIDs from MonitorMyWatershed
If you are sending data to monitor my watershed, it is much easier to create the variables in an array and then to paste the UUID's all together as copied from the "View Token UUID List" link for a site. If using this method, be very, very, very careful to make sure the order of your variables exactly matches the order of your UUID's.
Creating Variables within an Array
You can also create and name variable pointer objects outside of the array (as is demonstrated in all of the code chunks here) and then reference those pointers inside of the array like so:
The Logger Object
Now that we've created the array, we can actually create the Logger object.
Data Publishers
Here we set up all three possible data publisers and link all of them to the same Logger object.
Monitor My Watershed
To publish data to the Monitor My Watershed / EnviroDIY Data Sharing Portal first you must register yourself as a user at https:/
DreamHost
It is extrmemly unlikely you will use this. You should ignore this section.
ThingSpeak
After you have set up channels on ThingSpeak, you can use this code to publish your data to it.
Keep in mind that the order of variables in the VariableArray is crucial when publishing to ThingSpeak.
Ubidots
Use this to publish data to Ubidots.
Extra Working Functions
Here we're creating a few extra functions on the global scope. The flash function is used at board start up just to give an indication that the board has restarted. The battery function calls the ProcessorStats sensor to check the battery level before attempting to log or publish data.
Arduino Setup Function
This is our setup function. In Arduino coding, the classic "main" function is replaced by two functions: setup() and loop(). The setup() function runs once when the board boots or restarts. It usually contains many functions that set the mode of input and output pins and prints out some debugging information to the serial port. These functions are frequently named "begin". Because we have a lot of parts to set up, there's a lot going on in this function!
Let's break it down.
Starting the Function
First we just open the function definitions:
Wait for USB
Next we wait for the USB debugging port to initialize. This only applies to SAMD and 32U4 boards that have built-in USB support. This code should not be used for deployed loggers; it's only for using a USB for debugging.
Printing a Hello
Next we print a message out to the debugging port. This is also just for debugging - it's very helpful when connected to the logger via USB to see a clear indication that the board is starting
Serial Interrupts
If we're using either NeoSWSerial or SoftwareSerial_ExtInts we need to assign the data receiver pins to interrupt functionality here in the setup.
The NeoSWSerial and SoftwareSerial_
NOTE: If you create more than one NeoSWSerial or Software serial object, you need to call the enableInterrupt function for each Rx pin!
For NeoSWSerial we use:
For SoftwareSerial with External interrupts we use:
Serial Begin
Every serial port setup and used in the program must be "begun" in the setup function. This section calls the begin functions for all of the various ports defined in the Extra Serial Ports section
SAMD Pin Peripherals
After beginning all of the serial ports, we need to set the pin peripheral settings for any SERCOM's we assigned to serial functionality on the SAMD boards. These were created in the Extra Serial Ports section above. This does not need to be done for an AVR board (like the Mayfly).
Flash the LEDs
Like printing debugging information to the serial port, flashing the board LED's is a very helpful indication that the board just restarted. Here we set the pin modes for the LED pins and flash them back and forth using the greenredflash() function we created back in the working functions section.
Begin the Logger
Next get ready and begin the logger. We set the logger time zone and the clock time zone. The clock time zone is what the RTC will report; the logger time zone is what will be written to the SD card and all data publishers. The values are set with the Logger::
prefix because they are static variables of the Logger class rather than member variables. Here we also tie the logger and modem together and set all the logger pins. Then we finally run the logger's begin function.
Setup the Sensors
After beginning the logger, we setup all the sensors. Unlike all the previous chuncks of the setup that are preparation steps only requiring the mcu processor, this might involve powering up the sensors. To prevent a low power restart loop, we put a battery voltage condition on the sensor setup. This prevents a solar powered board whose battery has died from continuously restarting as soon as it gains any power on sunrise. Without the condition the board would boot with power, try to power hungry sensors, brown out, and restart over and over.
Custom Modem Setup
Next we can opt to do some special setup needed for a few of the modems. You should only use the one chunk that applies to your specific modem configuration and delete the others.
ESP8266 Baud Rate
This chunk of code reduces the baud rate of the ESP8266 from its default of 115200 to 9600. This is only needed for 8MHz boards (like the Mayfly) that cannot communicate at 115200 baud.
Skywire Pin Inversions
This chunk of code inverts the pin levels for status, wake, and reset of the modem. This is necessary for the Skywire development board and some other breakouts.
SimCom SIM7080G Network Mode
This chunk of code sets the network mode and preferred mode for the SIM7080G.
XBee Cellular Carrier
This chunk of code sets the carrier profile and network technology for a Digi XBee or XBee3. You should change the lines with the CP
and N#
commands to the proper number to match your SIM card.
SARA R4 Cellular Carrier
This chunk of code sets the carrier profile and network technology for a u-blox SARA R4 or N4 module, including a Sodaq R410 UBee or a Digi XBee3 LTE-M in bypass mode.. You should change the lines with the UMNOPROF
and URAT
commands to the proper number to match your SIM card.
Sync the Real Time Clock
After any special modem options, we can opt to use the modem to synchronize the real time clock with the NIST time servers. This is very helpful in keeping the clock from drifting or resetting it if it lost time due to power loss. Like the sensor setup, we also apply a battery voltage voltage condition before attempting the clock sync. (All of the supported modems are large power eaters.) Unlike the sensor setup, we have an additional check for "sanity" of the clock time. To be considered "sane" the clock has to set somewhere between 2020 and 2025. It's a broad range, but it will automatically flag values like Jan 1, 2000 - which are the default start value of the clock on power up.
Setup File on the SD card
We're getting close to the end of the setup function! This section verifies that the SD card is communicating with the MCU and sets up a file on it for saved data. Like with the sensors and the modem, we check for battery level before attempting to communicate with the SD card.
Sleep until the First Data Collection Time
We're finally fished with setup! This chunk puts the system into low power deep sleep until the next logging interval.
Setup Complete
Set up is done! This setup function is really long. But don't forget you need to close it with a final curly brace.
Arduino Loop Function
This is the loop function which will run repeatedly as long as the board is turned on. NOTE: This example has code for both a typical simple loop and a complex loop that calls lower level logger functions. You should only pick one loop function and delete the other.
A Typical Loop
After the incredibly long setup function, we can do the vast majority of all logger work in a very simple loop function. Every time the logger wakes we check the battery voltage and do 1 of three things:
- If the battery is very low, go immediately back to sleep and hope the sun comes back out
- If the battery is at a moderate level, attempt to collect data from sensors, but do not attempt to publish data. The modem the biggest power user of the whole system. 3.
At full power, do everything.
A Complex Loop
If you need finer control over the steps of the logging function, this code demonstrates how the loop should be constructed.
Here are some guidelines for writing a loop function:
- If you want to log on an even interval, use
if (checkInterval())
orif (checkMarkedInterval())
to verify that the current or marked time is an even interval of the logging interval.. - Call the
markTime()
function if you want associate with a two iterations of sensor updates with the same timestamp. This allows you to usecheckMarkedInterval()
to check if an action should be preformed based on the exact time when the logger woke rather than upto several seconds later when iterating through sensors. - Either:
- Power up all of your sensors with
sensorsPowerUp()
. - Wake up all your sensors with
sensorsWake()
. - Update the values all the sensors in your VariableArray together with
updateAllSensors()
. - Immediately after running
updateAllSensors()
, put sensors to sleep to save power withsensorsSleep()
. - Power down all of your sensors with
sensorsPowerDown()
.
- Power up all of your sensors with
- Or:
- Do a full update loop of all sensors, including powering them with
completeUpdate()
. (This combines the previous 5 functions.)
- Do a full update loop of all sensors, including powering them with
- After updating the sensors, then call any functions you want to send/print/save data.
- Finish by putting the logger back to sleep, if desired, with
systemSleep()
.
All together, this gives:
If you need more help in writing a complex loop, the double_