Firmware for the ATTNode v3 https://www.attno.de/12-attnode_v3
Go to file
2021-04-06 16:09:08 +02:00
.vscode Refactored Sensor Libraries to use Common Interface 2021-02-01 21:21:03 +01:00
include Fix Calibration Routines 2021-03-31 20:15:13 +02:00
lib Enable Calibration on Sensair S8 2021-04-06 16:09:08 +02:00
src Fix Calibration Routines 2021-03-31 20:15:13 +02:00
.gitignore Refactored Sensor Libraries to use Common Interface 2021-02-01 21:21:03 +01:00
LICENSE Add License File 2021-03-03 21:44:13 +01:00
platformio.ini WS2812B Code Cleanup, Configuration via config.h 2021-03-09 17:30:34 +01:00
README.md Fix Payload Decoder Template 2021-03-31 16:53:16 +02:00

ATTNode v3 Firmware

Documentation

The full documentation for firmware options, payload decoders and programming can be found at attno.de

Configuration and Programming

This is the code repository for ATTNode v3 compatible firmware. At the moment it supports LoRa communication using OTAA and a BME280 or SHT21 sensor, as well as deep sleep between measurements.

The firmware is developed using PlatformIO. At least version 5.1.0 is needed for ATTiny3216 support.

To set the fuses for clock speed, BOD levels etc., use the "Set Fuses" operation in PlatformIO. This has to be done once for a "fresh" Node or when the Board Config in platformio.ini was changed. Afterwards it is enough to use the normal "Upload" function for Code or config.h changes.

Before programming a node, copy src/config.h.example to src/config.h and set the used sensor, LoRaWAN keys and other options as needed.

Programming is done using a MicroUPDI Programmer, settings in platformio.ini are set to use it. For other pogrammer options see the PlatformIO Documentation

Payload Decoder

You need to specify a Payload Decoder fitting for your configured Sensors for a Node. The Following code Shows an example for a Payload Decoder usable with TTN Stack v3. Uncomment the Parts for your used sensors. There is a Start and End comment for each possible sensor/value, uncomment the Lines between them (The ones starting with //) to activate the Decoding for a particular Sensor. Be aware that there might be an overlap in the sensor namings for sensors with the same Values (e.g. SCD30 and BME280/SHT21 all report Temperature and Humidity. If you use them in parallel you might want to change the names of the decoded fields).

function bytesToInt16(bytes, start) {
  var out  = ((bytes[start]) | (bytes[start+1] << 8 ));
  var sign = bytes[start+1] & (1 << 7);
  if (sign)
    out = 0xFFFF0000 | out;
  return out;
}

function bytesToUInt16(bytes, start) {
  return ((bytes[start]) | (bytes[start+1] << 8 ));
}

function bytesToInt32(bytes, start) {
  return ((bytes[start]) | (bytes[start+1] << 8) | (bytes[start+2] << 16) | (bytes[start+3] << 24));
}

function decodeUplink(input) {
  var decoded = {};
  /* Battery Voltage, always enabled */
  decoded.v = (input.bytes[0] * 20) / 1000.0;
  
  var i = 1;
  /* Start CO2-Sensor (SG112A, MH-Z19C, Sensair S8, Sensirion SCD30) PPM */
  // decoded.ppm = bytesUToInt16(input.bytes, i);
  // i += 2;
  /* End CO2 Sensor PPM */

  /* Start Temperature + Humidity SCD30 */
  // decoded.t = bytesToInt16(input.bytes, i)/100;
  // decoded.h = bytesUToInt16(input.bytes, i+2)/100;
  // i += 4;
  /* End Temperature + Humidity SCD30 */
  
  /* Start Temperature and Humidity (SHT21) */
  // decoded.t = bytesToInt32(input.bytes, i)/100;
  // decoded.h = bytesToInt32(input.bytes, i+4)/100;
  // i += 8;
  /* End Temperature + Humidity BME/SHT */
  
  /* Start Temperature, Humidity, Atmospheric Pressure (BME280) */
  // decoded.t = bytesToInt32(input.bytes, i)/100;
  // decoded.h = bytesToInt32(input.bytes, i+4)/100;
  // decoded.p = bytesToInt32(input.bytes, i+8)/100;
  // i += 12;
  /* End Atmospheric Pressure

  /* Start DS18B20 Temperatures 
     Will append all recognized Sensors as t1, t2, t3... */
  // var n = 1;
  // for (var j = i; j < input.bytes.length-1; j+=2) {
  //   decoded["t" + n] = bytesToInt16(input.bytes, j)/100;
  //   n++;
  // }
  /* End DS18B20 Temperatures */

  /* Leave this part as is */
  return {
    data: decoded,
    warnings: [],
    errors: []
  };
}

Please be also aware, that not all sensor combinations are valid. Some might use the same interface and interfere with each others readings. Also keep in mind that RAM- and Flash-Space are limited, which might lead to crashes or the code not compiling/flashing correctly if to many sensors are enabled at the same time.

It is possible to change the sending interval via Downlink-Packets at runtime. The time between Transmits is specified in minutes (or more exactly, 64 Second intervals) and has to be sent as a 2 byte value, which will be interpreted as an uint. so for example 0x0001 means 1 Minute, 0x0002 means 2 Minutes and so on. Sending 0xFFFF resets the value to the compiled in default.

Acknowledgements

Parts of this code where kindly provided by @shempe