Add A Sensor - mxtommy/SigkSens GitHub Wiki

After you have SigkSens working with the test sensors, as documented in Getting Started, it's time to start adding actual sensors. This document describes in detail how to do that. We'll start by describing how sensors are enabled and configured, then give the details of all the available types of sensors, and finish with the step-by-step procedure for adding a sensor.

Enabling and Configuring Sensors

By default, the only sensor that's enabled is the "Local" sensor, which isn't a sensor at all. But you know that by now, since you've been through the Getting Started document. To start using a real sensor, you have to:

  1. Physically connect it to your MCU, to the appropriate pins, with any necessary resistors, etc. That's not covered by the SigkSens documentation.

  2. Enable the type of sensor in the config.h file (which is located in the same folder as the main SigkSens .ino or .cpp file). Edit the file, and near the top, you'll see this:

// Sensors

#define ENABLE_SYSTEMHZ
//#define ENABLE_DIGITALIN
//#define ENABLE_DIGITALOUT
//#define ENABLE_ANALOGIN
//#define ENABLE_ONEWIRE

// if any of these are enabled, make sure ENABLE_I2C below is as well.
//#define ENABLE_I2C
//#define ENABLE_SHT30
//#define ENABLE_MPU
//#define ENABLE_BMP280
//#define ENABLE_ADS1115

As you can see, only the first #define line is not commented out. To enable a sensor type, remove the leading //. But don't enable any that you aren't going to use - at some point, enabling too many of them may overload the system and it may crash.

  1. Configure each sensor as described below.

Configuring a Sensor

Each time SigkSens starts, it scans the i2c and the 1-Wire bus for any recognized sensors.

Each sensor discovered will have a type and an address. The type is a numeric value that identifies what type of sensor it is. The address tells SigkSens where (in memory) to look for the data, and allows it to differentiate between multiple sensors of the same type. See table below.

Each sensor has one or more attributes, which represent the data the sensor can send to SignalK. For example, a 1-Wire temperature sensor has only one attribute: tempK (temperature in degrees Kelvin), but an SHT30 sensor has two attributes: tempK, and humidity. These are defined by SigkSens depending on sensor type. Each attribute has three parameters, which you configure: path, scale, and offset.

  • path is what identifies the data to each Consumer of SignalK data. For example, the path for the data collected by a temperature sensor on your flybridge might be "environment.outside.temperature", but a temperature sensor in your engine room might be "environment.inside.engineRoom.temperature". Without a path, the data would be meaningless, therefore, if the path isn't set for a particular attribute, it won't even be submitted to SignalK. (The full list of SignalK paths is here).

  • scale and offset are optional, and are used to correct the sensor's raw data before it's sent to SignalK. Scale will be multiplied by the raw value from the sensor: for example, 1.03. Offset is added to the result of (raw value from sensor x scale). It can be a positive or negative number: 3.4, -0.83, etc. Scale defaults to 1.0 and offset defaults to 0.0, so if you don't set them, they have no impact on your raw numbers.

You set parameters by simply running a long URL in your browser. This is how you might set all three parameters for your flybridge temperature sensor:

http://192.168.2.2/setSensorAttr?address=0x42&attrName=tempK&path=environment.outside.temp&scale=1.03&offset=-0.83

Sensor Types

ID Type Address Description
0 local Local MCU info, for testing
1 digitalIn D1 or D2 (see Note 1) Digital inputs (state/hz)
2 oneWire Note 2 1-Wire temperature probe
3 sht30 0x45 i2c temperature and humidity
4 mpu925x 0x68 i2c 9 axis IMU
5 bmp280 0x77 i2c barometric pressure
6 ads1115 0x48 i2c 16 bit 4 channel ADC
7 analogIn A0 MCU's built-in 10 bit ADC
8 digitalOut OUT1 or OUT1 (see Note 3) Digital output pins

Note 1: By default, you can connect one or two digitalIn sensors, to GPIO pins 14 and 12 on the Wemos D1 mini. The Address of pin 14 for this purpose is D1, and for pin 12, it's D2. (You can connect more than two, but doing so requires modification to the "Digital input pins" section of config.h. If you're using an MCU other than a Wemos D1 mini, your pin numbers will probably be different - change them in the "Digital input pins" section of config.h)

Note 2: All 1-Wire sensors will be connected to pin D7/GPIO13 on a Wemos D1 mini, and each one you connect will have a unique address. It will look like a MAC address - 28:02:45:2A:00:00:80:AC, for example. (If you're using an MCU other than a Wemos D1 mini, your pin numbers will probably be different - change them in the "Digital input pins" section of config.h) The first example of how to set up a sensor (later in this page) details how to get the address for a 1-Wire sensor.

Note 3: By default, you can connect one or two digitalOut "sensors", to GPIO pins 16 and 15 on the MCU. The Address of pin 16 for this purpose is OUT1, and for pin 15, it's OUT2. (You can connect more than two, but doing so requires modification to the "Digital output pins" section of config.h. If you're using an MCU other than a Wemos D1 mini, your pin numbers will probably be different - change them in the "Digital input pins" section of config.h)

Sensor Details

Several of the supported sensors communicate with the MCU through i2c. (If you're not familiar with i2c, the first section of this article has a good introduction to it.) SigkSens communicates with them as follows. At every MCU startup, the i2c bus is scanned for attached sensors at the addresses detailed in the table above. If a sensor is found, it's stored in the configuration, and its output is then available to be sent to SignalK (if you've set the Path for the particular sensor and value). Many i2c sensors can output their values on different addresses. SigkSens uses the most common default address for each sensor type, but your particular sensor may use one of the other available addresses. In that case, you need to change the address on the sensor: see the Data Sheet for your sensor for details.

Local

This sensor is useful for debugging. It outputs some information about the MCU, but more important, it allows you to see that data is flowing from the MCU to the Serial Monitor and to SignalK, even when you don't have an actual sensor connected.

Attribute Name Description
systemHz Number of times the main loop executed in 1 second
freeMem Number of free Bytes on the MCU
uptime Time since the last MCU reboot (in seconds)

Digital In

This sensor is used to get state change data from digital input pins on the MCU.

Attribute Name Description
state Current status of pin: LOW or HIGH
freq Number of LOW->HIGH changes in the past 1 second
count Total state changes* since the last time the MCU was restarted

*The default for counting state changes on a digital input pin is CHANGE, but you can change it to RISING or FALLING, for each pin, with the #define DIGITAL_INPUT_MODES line in config.h.

1-Wire Temperature

Multiple 1-Wire sensors are supported, including MAX31850 thermocouple boards. All must be connected to the same GPIO pin (D7/GPIO13).

Attribute Name Description
tempK Tempurature (degrees Kelvin)

SHT30 Temperature and Humidity

  • This sensor connects using i2c, so it must be connected to the SCL and SDA pins on the MCU (D1/GPIO5 and D2/GPIO4 on the Wemos D1 Mini and D1 Mini Lite - if you're using a different MCU, the pins will probably be different).
  • The MCU generates enough heat to add a few degrees to the reading if it's too close to the board, so if a super accurate temperature is important to you, it's best to put a bit of distance between the sensor and the MCU.
Attribute Name Description
tempK Tempurature (degrees Kelvin)
humidity Humidity (percent: 0-100)

Mpu925x 9-Axis IMU

  • This sensor connects using i2c, so it must be connected to the SCL and SDA pins on the MCU (D1/GPIO5 and D2/GPIO4 on the Wemos D1 Mini and D1 Mini Lite). It also uses an interrupt pin: D6/GPIO12 on the Mini and Mini Lite. If you're using a different MCU, the pins will probably be different.
  • SigkSens runs a sensor fusing algorithm to try to get usable output from the MPU925x. The onboard DSP is only a 6-axis fusion algorithm, so in order to fuse the magnetometer data as well we use our own fusion. Sensor MUST be calibrated in order to be useful! See instructions for calibration here.
  • The MCU generates enough heat to add a few degrees to the reading if it's too close to the board, so if a super accurate temperature is important to you, it's best to put a bit of distance between the sensor and the MCU.
Attribute Name Description
tempK Temperature of the MPU chip (degrees Kelvin)
yaw Yaw referenced to magnetic north (radians)
pitch Pitch referenced to "level" (radians)
roll Roll referenced to "level" (radians)
filterRate Number of times the sensor integration filter ran in one second (useful for troublehooting)

BMP280 Barometric Pressure and Temperature

  • This sensor connects using i2c, so it must be connected to the SCL and SDA pins on the MCU (D1/GPIO5 and D2/GPIO4 on the Wemos D1 Mini and D1 Mini Lite - if you're using a different MCU, the pins will probably be different).
  • The MCU generates enough heat to add a few degrees to the reading if it's too close to the board, so if a super accurate temperature is important to you, it's best to put a bit of distance between the sensor and the MCU.
Attribute Name Description
tempK Temperature (degrees Kelvin)
Pa Barometric pressure (Pascals)

ADS1115 4 x 16-bit ADC

  • This sensor connects using i2c, so it must be connected to the SCL and SDA pins on the MCU (D1/GPIO5 and D2/GPIO4 on the Wemos D1 Mini and D1 Mini Lite - if you're using a different MCU, the pins will probably be different).
  • In order to smooth data, many reads per second are taken, and are smoothed with a simple exponent filter. (Readings are taken only if the path is set.) Updates are sent every SLOW_LOOP_DELAY ms. Use scale and offset to convert millivolts to your desired final value if needed. (SLOW_LOOP_DELAY is 200ms by default. It can be changed in config.h, but it's used for other purposes besides this, so don't change it unless you fully understand the implications.)
Attribute Name Description
diff0_1 Differential voltage between inputs 0 and 1 (millivolts)
diff2_3 Differential voltage between inputs 2 and 3 (millivolts)
chan0 Voltage (referenced to GND) on input 0 (millivolts)
chan1 Voltage (referenced to GND) on input 1 (millivolts)
chan2 Voltage (referenced to GND) on input 2 (millivolts)
chan3 Voltage (referenced to GND) on input 3 (millivolts)

Analog 10-bit ADC

Reads from the built-in 10-bit ADC on the MCU (pin A0 on the Wemos D1 Mini and Mini Lite - if you're using a different MCU, the pin will probably be different). Could be used for monitoring voltage, bilge level, or anything else that has an analog sensor. Uses an exponential filter similar to the ADS1115 filter, to smooth data a bit. Use scale and offset to get the proper range for whatever you're measuring.

Attribute Name Description
a0 Value of the ADC (between 0 and 1024)

Usage: /setSensorAttr?address=A0&attrName=a0&path=

Digital Output

Use to control the world! For example, connect to a relay to power a really loud alarm buzzer. This is a work in progress. It also requires PUT support in the SignalK Node Server to work, which has not been released into NPM at this time. The MCU will report the current state of the output to the path set. It will also listen for PUT requests to that Signalk path.

Output pins can be defined in config.h. Defaults to pins D0/GPIO16 and D8/GPIO15 on the Wemos D1 Mini and Mini Lite.

Attribute Name Description
state Current state (on=true, off=false) of the output. Defaults to off at startup.

API

There's a very simple API used to get information or set parameters. All requests are GET for simplicity. In the examples below, replace "1.2.3.4" with the IP address of your MCU.

/getSensorInfo

Returns a list of all global configuration data, and sensors and their configuration. Output looks like this:

{"hostname":"WemosD1Lite","signalKHost":"","signalKPort":80,"signalKPath":"/signalk/v1/stream","signalKToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImJ1dGNoIiwiaWF0IjoxNTM3ODEyNTIyLCJleHAiOjQ2NjIwMTQ5MjJ9.r2iwVvwPjrtRt40_Mapw2h1Ll2Ze9LV026l67QhTJT8","websocketClientConnectedHost":"192.168.0.58","websocketClientConnectedPort":3000,"websocketClientConnected":true,"sensors":[{"address":"Local","type":0,"attrs":[{"name":"systemHz","signalKPath":"sensors.WemosD1Lite.systemHz","value":"50535.00"},{"name":"freeMem","signalKPath":"sensors.WemosD1Lite.freeMem","value":"20096"},{"name":"uptime","signalKPath":"sensors.WemosD1Lite.uptime","value":"32.60"}]},{"address":"28:02:45:2A:00:00:80:AC","type":2,"attrs":[{"name":"tempK","signalKPath":"environment.outside.temp","value":"null"}]}]}

Usage: http://1.2.3.4/getSensorInfo

/setSensorAttr

Sets the parameters of a sensor.

Required HTTP parameters:

  • address: address of the sensor. (e.g., "0x42" for an i2c sensor.) See Sensor Types table above.

  • attrName: name of the attribute to set parameters for (e.g., "tempK").

  • path: sets the Signalk Path of the attribute (e.g., "environment.outside.temp").

  • scale: OPTIONAL - is 1.0 by default. Raw value from the sensor is multiplied by this to make minor correction to the raw sensor value (e.g., "1.03"), or to tailor the output to whatever you're actually measuring.

  • offset: OPTIONAL - is 0.0 by default. The amount added to the scaled value (raw value x scale value). For substraction, use a negative number (e.g., "2.0" or "-3.345").

example: here's how you might set the attributes for the temperature output of an SHT30 sensor:

http://1.2.3.4/setSensorAttr?address=0x45&attrName=tempK&path=environment.outside.temp&scale=1.02&offset=3.6

/setNewHostname

This command sets a new hostname for the MCU. Note that this causes the MCU to reboot!

Required HTTP parameters:

  • hostname: new hostname, maximum 16 characters, use only numbers and letters to be safe.

example: http://1.2.3.4/setNewHostname?hostname=engRoomWemosD1

/setSignalKHost

Used to manually set the IP address of the Signalk server. Not needed if the server is detected via mDNS. Default value is blank.

Required HTTP parameters:

  • host: IP address of SignalK server

example: http://1.2.3.4/setSignalKHost?host=192.168.10.1

/setSignalKPort

Used to manually set the port of the Signalk Node Server. Not needed if server is detected via mDNS. Default value is 80.

Required HTTP parameters:

  • port: port number of SignalK Node Server

example: http://1.2.3.4/setSignalKPort?port=3000

/setSignalKPath

Used to manually set the URL of the signalk server. Default: "/signalk/v1/stream". Not needed if server is detected via mDNS. Should never really change.

Required HTTP parameters:

  • path: URL (path) of SignalK Server

example: http://1.2.3.4/setSignalKPath?path=/signalk/v2/stream

/setSignalKToken

Used to set the security token that's required when connecting to the SignalK server. Default is blank - and it won't work without one.

Required HTTP parameters:

  • token: Token issued by the SignalK Server

example: http://1.2.3.4/setSignalKToken?token=3ueo5w3$%6tk2oej1soiep5W#59gRRT

Sensor Configuration Example 1: 1-Wire Temperature Sensor

The first sensor will be a 1-Wire temperature sensor. 1-Wire refers to a proprietary protocol for temperature sensors produced by Dallas Semiconductor (now Maxim). They are extremely easy to use, and more than 200 of them can be daisy-chained together to a single MCU. (Much more information is available here.)

  1. Connect the Sensor to the MCU

The connection is very simple: all you need is the MCU, the sensor, and a 4.7K resistor. The image below shows the connection to an Arduino Uno, but the connection to your MCU will be the same, except:

  • the green DATA wire will go to pin D7/GPIO13 on the Wemos D1 mini / mini Lite
  • the red "power in" wire will go to the 3.3V pin on the Wemos

ds18b20 hookup diagram

  1. In config.h, change the line:

//#define ENABLE_ONEWIRE

to

#define ENABLE_ONEWIRE

(i.e., remove the two leading slashes to "un-comment" it), then save the file.

  1. Compile and upload the program to the MCU.

  2. Open the Serial Monitor, turn off auto-scroll, then push the restart button on the MCU, so you can see all the startup output. You'll see a few lines that refer to 1-Wire:

1-Wire Parasite power is: OFF
1-Wire Device precision currently: 9 setting to 10 Done!
Starting 1-Wire scanning timer at: 30000ms
Scanning 1-Wire Bus
starting webserver
Ready!

This tells you that your 1-Wire sensor was found, and should be ready to be configured.

  1. A few lines above that in the serial output, you'll see info about the sensor, including the address:
     "address": "28:02:45:2A:00:00:80:AC",
      "type": 2,
      "attrs": [
        {
          "name": "tempK",
          "signalKPath": "",
          "value": ""

The address, in this case (because it's 1-Wire sensor) is a really big number because every 1-Wire sensor manufactured has a unique address. SigkSens knows it's a 1-Wire sensor, so it shows the type is 2, and that means it has only one attribute, named "tempK". The signalKPath is still blank, because you haven't set it yet, and it won't output any value until you set the path.

  1. Set the path, so data will be output. In a browser, run: http://192.168.0.8/setSensorAttr?address=28:02:45:2A:00:00:80:AC&attrName=tempK&path=environment.outside.temp

The example uses environment.outside.temp for the path. It could be any valid SignalK path, or one that you make up, like environment.sigksensTempTest.temp. Whatever you choose will display all the places we've seen data display so far, except maybe the SignalK Instrument Panel. However, you should probably stick to the defined specification to make sure that any Consumers of SignalK data that you ever use will know how to display your data.

Running setSensorAttr will cause the MCU to restart, and then it should start outputting the data from your new sensor. The quickest way to see it is to run http://1.2.3.4 in your browser (changing "1.2.3.4" to the actual IP address of your MCU, of course).

And if you bring up the SignalK Instrument Panel, you should see a new display for the new sensor:

instrument panel environment outside temp

Sensor Configuration Example 2: DigitalIn

The second and final example will be a tachometer for the main engine, based on an infrared transmitter / receiver. The example doesn't have a lot of details.

  1. Physically connect the sensor to the MCU, and attach a small patch of reflective tape on the engine's harmonic balancer.

  2. Enable DIGITALIN in config.h.

  3. Modify the DIGITAL_INPUT_MODES values if necessary. (i.e., if you want to count RISING or FALLING instead of CHANGE.)

  4. Compile and upload to the MCU.

  5. Set the "freq" attribute of the digitalIn sensor:

http://1.2.3.4/setSensorAttr?address=D1&attrName=freq&path=propulsion.mainEngine.revolutions&scale=0.5

  • D1 comes from the Sensor Types Table.
  • Scale and offset aren't needed, since "revolutions" in SignalK is "revolutions per second", and that's what "freq" outputs.
  1. The MCU will restart when you run /setSensorAttr, and when it comes back up, it will start outputting the main engine's RPM to SignalK as propulsion.mainEngine.revolutions.

Summary

At this point, you should be able to add any of the supported sensors on your own, figuring out all the details from what has been written above, and your sensor's Datasheet. Follow the general steps in the DigitalIn example for each one.

If you have issues, try reaching the developers at https://signalk-dev.slack.com, in the #sensors Channel.

Using my_config.h to Store Your Configuration Settings

The file config.h consists of several #define statements for a number of settings. For example, if you are using a DigitalIn sensor, you will have uncommented the #define ENABLE_DIGITALIN line, and you may have modified the #define DIGITAL_INPUT_MODES{CHANGE, CHANGE} line. The next time you update the SigkSens source files, however, you're going to get a new config.h file that will overwrite those changes. (And it may contain some new configuration options, so you can't simply save your old config.h file and copy it in place of the new one.) Using a my_config.h file for your settings allows you to save them from one version of SigkSens to the next.

Create a new text file named my_config.h, in the same folder as the config.h file. It will contain only the #define statements that you need to enable or modify for your particular combination of sensors. For example, if you're using DigitalIn and an SHT30 temp/humidity sensor, your my_config.h might look like this:

#define ENABLE_DIGITALIN
#define DIGITAL_INPUT_MODES{RISING, CHANGE}
// if any of these are enabled, make sure to uncomment ENABLE_I2C below is as well.
#define ENABLE_I2C
#define ENABLE_SHT30

To use that file, go to the very end of config.h and uncomment the line // #include "my_config.h". Do that every time you download source code for SigkSens, and the #define statements in your my_config.h file will be used instead of the ones in config.h.

PRO TIP: If you're using multiple MCU's around the boat, each one of them is likely to have a different combination of sensors, and each of them would need its own my_config.h file. There's nothing magical about the name "my_config.h" - you could have an "engroom_config.h" and a "flybridge_config.h". Then, when you're ready to compile for the engine room MCU, either copy "engroom_config.h" to "my_config.h", or make the last line of the config.h file be #include "engroom_config.h" - either approach will use the settings in engroom_config.h.

MPU925X Calibration

Note - don't forget that you must connect the interrupt pin. (D6 / GPIO12 on the Wemo D1 min and min Lite)

If there's an MPU925X 9-axis IMU connected, it must be calibrated following these two steps.

Accelerometer and Gyroscope Calibration

Keep the sensor completely still and as level as you can make it - this tells the sensor what "level" is.

In your browser, run: http://1.2.3.4/mpuCalAccelGyro - there are no parameters. After a couple of seconds calibration will be done.

Magnetometer Calibration

  1. Start calibration by running http://1.2.3.4/mpuCalMagStart in your browser. No MPU data will be sent to SignalK during this calibration.

  2. Standing in the center of a room, at least 5 feet away from anything electric or magnetic or metallic, rotate the sensor in every direction through all three axis. Do this for at least 20 seconds.

  3. Finish the calibration by running http://1.2.3.4/mpuCalMagStop in your browser. This saves the generated calibration and puts the MPU back into normal mode.