bring repo up-to-date
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <HX711_ADC.h>
|
||||||
|
|
||||||
|
//HX711 constructor (dout pin, sck pin)
|
||||||
|
HX711_ADC LoadCell_1(A3, A2); //HX711 1
|
||||||
|
HX711_ADC LoadCell_2(A1, A0); //HX711 2
|
||||||
|
|
||||||
|
long t;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600); delay(10);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Starting...");
|
||||||
|
LoadCell_1.begin();
|
||||||
|
LoadCell_2.begin();
|
||||||
|
long stabilisingtime = 2000; // tare preciscion can be improved by adding a few seconds of stabilising time
|
||||||
|
byte loadcell_1_rdy = 0;
|
||||||
|
byte loadcell_2_rdy = 0;
|
||||||
|
while ((loadcell_1_rdy + loadcell_2_rdy) < 2) { //run startup, stabilization and tare, both modules simultaniously
|
||||||
|
if (!loadcell_1_rdy) loadcell_1_rdy = LoadCell_1.startMultiple(stabilisingtime);
|
||||||
|
if (!loadcell_2_rdy) loadcell_2_rdy = LoadCell_2.startMultiple(stabilisingtime);
|
||||||
|
}
|
||||||
|
LoadCell_1.setCalFactor(100); // user set calibration value (float)
|
||||||
|
LoadCell_2.setCalFactor(100); // user set calibration value (float)
|
||||||
|
Serial.println("Startup + tare is complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
//update() should be called at least as often as HX711 sample rate; >10Hz@10SPS, >80Hz@80SPS
|
||||||
|
//longer delay in scetch will reduce effective sample rate (be carefull with use of delay() in the loop)
|
||||||
|
LoadCell_1.update();
|
||||||
|
LoadCell_2.update();
|
||||||
|
|
||||||
|
//get smoothed value from data set + current calibration factor
|
||||||
|
if (millis() > t + 250) {
|
||||||
|
long a = LoadCell_1.getSingleConversionRaw();
|
||||||
|
long b = LoadCell_2.getSingleConversionRaw();
|
||||||
|
Serial.print("Load_cell 1 output val: ");
|
||||||
|
Serial.print(a);
|
||||||
|
Serial.print(" Load_cell 2 output val: ");
|
||||||
|
Serial.println(b);
|
||||||
|
t = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <HX711_ADC.h>
|
||||||
|
|
||||||
|
//HX711 constructor (dout pin, sck pin)
|
||||||
|
HX711_ADC LoadCell_1(A3, A2); //HX711 1
|
||||||
|
HX711_ADC LoadCell_2(A1, A0); //HX711 2
|
||||||
|
|
||||||
|
long t;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600); delay(10);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Starting...");
|
||||||
|
LoadCell_1.begin();
|
||||||
|
LoadCell_2.begin();
|
||||||
|
long stabilisingtime = 2000; // tare preciscion can be improved by adding a few seconds of stabilising time
|
||||||
|
byte loadcell_1_rdy = 0;
|
||||||
|
byte loadcell_2_rdy = 0;
|
||||||
|
while ((loadcell_1_rdy + loadcell_2_rdy) < 2) { //run startup, stabilization and tare, both modules simultaniously
|
||||||
|
if (!loadcell_1_rdy) loadcell_1_rdy = LoadCell_1.startMultiple(stabilisingtime);
|
||||||
|
if (!loadcell_2_rdy) loadcell_2_rdy = LoadCell_2.startMultiple(stabilisingtime);
|
||||||
|
}
|
||||||
|
LoadCell_1.setCalFactor(100); // user set calibration value (float)
|
||||||
|
LoadCell_2.setCalFactor(100); // user set calibration value (float)
|
||||||
|
Serial.println("Startup + tare is complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
//update() should be called at least as often as HX711 sample rate; >10Hz@10SPS, >80Hz@80SPS
|
||||||
|
//longer delay in scetch will reduce effective sample rate (be carefull with use of delay() in the loop)
|
||||||
|
LoadCell_1.update();
|
||||||
|
LoadCell_2.update();
|
||||||
|
|
||||||
|
//get smoothed value from data set + current calibration factor
|
||||||
|
if (millis() > t + 250) {
|
||||||
|
long a = LoadCell_1.getSingleConversionRaw();
|
||||||
|
long b = LoadCell_2.getSingleConversionRaw();
|
||||||
|
Serial.print("Load_cell 1 output val: ");
|
||||||
|
Serial.print(a);
|
||||||
|
Serial.print(" Load_cell 2 output val: ");
|
||||||
|
Serial.println(b);
|
||||||
|
t = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include <hal/hal.h>
|
#include <hal/hal.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include "HX711.h"
|
#include "HX711.h"
|
||||||
#include "Adafruit_Si7021.h"
|
//#include "Adafruit_Si7021.h"
|
||||||
#include "Adafruit_FRAM_SPI.h"
|
#include "Adafruit_FRAM_SPI.h"
|
||||||
|
|
||||||
// Defines
|
// Defines
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,672 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_TxBuffer.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t *pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t *pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t *pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t *pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 4;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Versionierung des Paketformats
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Zehntels-Prozent
|
||||||
|
uint8_t pressure; // Luftdruck in XXXX
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der Messung in Sekunden, erster Wert ist 0
|
||||||
|
int16_t weight_raw1[MAX_VALUES_TO_SEND]; // Reading (raw) der ersten Waegzelle
|
||||||
|
int16_t weight_raw2[MAX_VALUES_TO_SEND]; // Reading (raw) der zweiten Waegzelle
|
||||||
|
int16_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/10 Grad Celsius
|
||||||
|
} LORA_data;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed (Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK
|
||||||
|
);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t *pJob);
|
||||||
|
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (! (gCatena.GetOperatingFlags() &
|
||||||
|
static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)))
|
||||||
|
{
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring)
|
||||||
|
);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena))
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t *pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM * const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep))
|
||||||
|
{
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS))
|
||||||
|
{
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() &
|
||||||
|
static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest)))
|
||||||
|
{
|
||||||
|
if (! gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
startSendingUplink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
|
||||||
|
gCatena.poll();
|
||||||
|
|
||||||
|
/* for mfg test, don't tx, just fill -- this causes output to Serial */
|
||||||
|
if (gCatena.GetOperatingFlags() &
|
||||||
|
static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))
|
||||||
|
{
|
||||||
|
TxBuffer_t b;
|
||||||
|
fillBuffer(b);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ReadSensors()
|
||||||
|
{
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int) (vBat * 1000.0f));
|
||||||
|
lora_data.vbat = (vBat * 1000 / 20);
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int) (vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
if (fBme)
|
||||||
|
{
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int) m.Temperature,
|
||||||
|
(int) m.Pressure,
|
||||||
|
(int) m.Humidity
|
||||||
|
);
|
||||||
|
lora_data.temperature[0] = m.Temperature;
|
||||||
|
lora_data.humidity = m.Temperature;
|
||||||
|
lora_data.pressure = m.Pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.wait_ready_timeout(1000))
|
||||||
|
{
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not found.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.wait_ready_timeout(1000))
|
||||||
|
{
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not found.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fillBuffer(TxBuffer_t &b)
|
||||||
|
{
|
||||||
|
b.begin();
|
||||||
|
FlagsSensor2 flag;
|
||||||
|
|
||||||
|
flag = FlagsSensor2(0);
|
||||||
|
|
||||||
|
b.put(FormatSensor2); /* the flag for this record format */
|
||||||
|
uint8_t * const pFlag = b.getp();
|
||||||
|
b.put(0x00); /* will be set to the flags */
|
||||||
|
|
||||||
|
// vBat is sent as 5000 * v
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int) (vBat * 1000.0f));
|
||||||
|
b.putV(vBat);
|
||||||
|
flag |= FlagsSensor2::FlagVbat;
|
||||||
|
|
||||||
|
// vBus is sent as 5000 * v
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int) (vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
uint32_t bootCount;
|
||||||
|
if (gCatena.getBootCount(bootCount))
|
||||||
|
{
|
||||||
|
b.putBootCountLsb(bootCount);
|
||||||
|
flag |= FlagsSensor2::FlagBoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fBme)
|
||||||
|
{
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int) m.Temperature,
|
||||||
|
(int) m.Pressure,
|
||||||
|
(int) m.Humidity
|
||||||
|
);
|
||||||
|
b.putT(m.Temperature);
|
||||||
|
b.putP(m.Pressure);
|
||||||
|
b.putRH(m.Humidity);
|
||||||
|
|
||||||
|
flag |= FlagsSensor2::FlagTPH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.wait_ready_timeout(1000))
|
||||||
|
{
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not found.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.wait_ready_timeout(1000))
|
||||||
|
{
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not found.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
*pFlag = uint8_t(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startSendingUplink(void)
|
||||||
|
{
|
||||||
|
TxBuffer_t b;
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
fillBuffer(b);
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16))
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//gLoRaWAN.SendBuffer(b.getbase(), b.getn(), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*) &lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void *pContext,
|
||||||
|
bool fStatus
|
||||||
|
)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (! fStatus)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime()+sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t *pSendJob
|
||||||
|
)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t *pSendJob
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (! g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest)
|
||||||
|
{
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr())
|
||||||
|
{
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17))
|
||||||
|
{
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() &
|
||||||
|
static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0)
|
||||||
|
{
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay
|
||||||
|
);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n)
|
||||||
|
{
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000)
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100)
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t *pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t *pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(
|
||||||
|
osjob_t *pJob
|
||||||
|
)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(
|
||||||
|
osjob_t *pJob
|
||||||
|
)
|
||||||
|
{
|
||||||
|
startSendingUplink();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,978 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
CATCFG_T_CYCLE_INITIAL = 30, // every 30 seconds initially
|
||||||
|
CATCFG_INTERVAL_COUNT_INITIAL = 30, // repeat for 15 minutes
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
CATCFG_T_MIN = CATCFG_T_OVERHEAD,
|
||||||
|
CATCFG_T_MAX = CATCFG_T_CYCLE < 60 * 60 ? 60 * 60 : CATCFG_T_CYCLE, // normally one hour max.
|
||||||
|
CATCFG_INTERVAL_COUNT = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// the cycle time to use
|
||||||
|
unsigned gTxCycle;
|
||||||
|
// remaining before we reset to default
|
||||||
|
unsigned gTxCycleCount;
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
static Arduino_LoRaWAN::ReceivePortBufferCbFn receiveMessage;
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount);
|
||||||
|
|
||||||
|
// Additional Commands
|
||||||
|
// forward reference to the command function
|
||||||
|
cCommandStream::CommandFn cmdHello;
|
||||||
|
cCommandStream::CommandFn cmdGetCalibrationSettings;
|
||||||
|
cCommandStream::CommandFn cmdGetSensorReadings;
|
||||||
|
cCommandStream::CommandFn cmdGetScale1;
|
||||||
|
cCommandStream::CommandFn cmdGetScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale2;
|
||||||
|
|
||||||
|
// the individual commmands are put in this table
|
||||||
|
static const cCommandStream::cEntry sMyExtraCommmands[] =
|
||||||
|
{
|
||||||
|
{ "hello", cmdHello },
|
||||||
|
{ "get_calibration_settings", cmdGetCalibrationSettings },
|
||||||
|
{ "get_sensor_readings", cmdGetSensorReadings },
|
||||||
|
{ "calibrate_zero_scale1", cmdCalibrateZeroScale1 },
|
||||||
|
{ "calibrate_zero_scale2", cmdCalibrateZeroScale2 },
|
||||||
|
{ "calibrate_scale1", cmdCalibrateScale1 },
|
||||||
|
{ "calibrate_scale2", cmdCalibrateScale2 },
|
||||||
|
// other commands go here....
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a top-level structure wraps the above and connects to the system table */
|
||||||
|
/* it optionally includes a "first word" so you can for sure avoid name clashes */
|
||||||
|
static cCommandStream::cDispatch
|
||||||
|
sMyExtraCommands_top(
|
||||||
|
sMyExtraCommmands, /* this is the pointer to the table */
|
||||||
|
sizeof(sMyExtraCommmands), /* this is the size of the table */
|
||||||
|
"application" /* this is the "first word" for all the commands in this table*/
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
// must be 65 bytes long...
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
long cal_w2_0; // 4 Bytes, Wert Waegezelle 2 ohne Gewicht
|
||||||
|
float cal_w1_factor; // 4 Bytes,
|
||||||
|
float cal_w2_factor;
|
||||||
|
byte fill[49];
|
||||||
|
} __attribute__((packed)) CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur (Startwert) in 1/10 Grad Celsius
|
||||||
|
int8_t temperature_change[MAX_VALUES_TO_SEND - 1]; // Unterschied Temperatur seit letztem Messwert in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading; // Zeitunterschied letzte zu erste Messung (in Minuten)
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} SENSOR_data;
|
||||||
|
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
SENSOR_data last_sensor_reading;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
// Use D10 to regulate power
|
||||||
|
pinMode(D10, OUTPUT);
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
//setup_scales();
|
||||||
|
|
||||||
|
/* for 4451, we need wider tolerances, it seems */
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
LMIC_setClockError(10 * 65536 / 100);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* add our application-specific commands */
|
||||||
|
gCatena.addCommands(
|
||||||
|
sMyExtraCommands_top,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
// read config_data from fram...
|
||||||
|
gCatena.SafePrintf("Reading Calibration Config from FRAM...\n");
|
||||||
|
gCatena.getFram()->getField(cFramStorage::kBme680Cal, (uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("cal_w1_0: %d\n", config_data.cal_w1_0);
|
||||||
|
gCatena.SafePrintf("cal_w2_0: %d\n", config_data.cal_w2_0);
|
||||||
|
gCatena.SafePrintf("cal_w1_factor: %d.%03d\n", (int)config_data.cal_w1_factor, (int)(config_data.cal_w1_factor * 1000) % 1000);
|
||||||
|
gCatena.SafePrintf("cal_w2_factor: %d.%03d\n", (int)config_data.cal_w2_factor, (int)(config_data.cal_w2_factor * 1000) % 1000);
|
||||||
|
gCatena.SafePrintf("Size of config_data: %d\n", sizeof(config_data));
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
//config_data.cal_w1_0 = 20000;
|
||||||
|
//config_data.cal_w2_0 = 20000;
|
||||||
|
//config_data.cal_w1_factor = 2.5;
|
||||||
|
//config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
|
||||||
|
// config_data speichern...
|
||||||
|
//gCatena.SafePrintf("Writing Calibration Config to FRAM...\n");
|
||||||
|
//gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SetReceiveBufferBufferCb(receiveMessage);
|
||||||
|
setTxCycleTime(CATCFG_T_CYCLE_INITIAL, CATCFG_INTERVAL_COUNT_INITIAL);
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Enable Power
|
||||||
|
digitalWrite(D10, HIGH);
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//LoadCell_1.power_down();
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(D12, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//LoadCell_2.power_down();
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.temperature = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
lora_data.temperature_change[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n", lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n", lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n", lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n", lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n", lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n", lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n", lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n", lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n", lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n", lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n", lora_data.temperature);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld", lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature_change\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND - 1; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.temperature_change[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetVBatValue(int millivolts)
|
||||||
|
{
|
||||||
|
uint8_t res;
|
||||||
|
if (millivolts <= 2510) {
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
} else if (millivolts >= 4295) {
|
||||||
|
res = 255;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = (millivolts - 2510) / 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime, bool readOnly)
|
||||||
|
{
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
int16_t temp_change;
|
||||||
|
int32_t weight_current32;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int16_t)((m.Temperature) * 10);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n", pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
// Setup Scales
|
||||||
|
setup_scales();
|
||||||
|
|
||||||
|
// Read Scales
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
//LoadCell_1.power_down();
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_2.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
//LoadCell_2.power_down();
|
||||||
|
|
||||||
|
// Disable Power
|
||||||
|
digitalWrite(D10, LOW);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current32 = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
if (weight_current32 < 0) {
|
||||||
|
weight_current32 = 0;
|
||||||
|
} else if (weight_current32 > UINT16_MAX) {
|
||||||
|
weight_current32 = UINT16_MAX;
|
||||||
|
}
|
||||||
|
weight_current = (uint16_t)weight_current32;
|
||||||
|
|
||||||
|
if (not(readOnly)) {
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
temp_last = lora_data.temperature;
|
||||||
|
|
||||||
|
for (int i = 0; i < my_position; i++) {
|
||||||
|
temp_last = temp_last + lora_data.temperature_change[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
if (my_position == 0) {
|
||||||
|
lora_data.temperature = temp_current;
|
||||||
|
} else {
|
||||||
|
temp_change = temp_current - temp_last;
|
||||||
|
if (temp_change > 127) {
|
||||||
|
temp_change = 127;
|
||||||
|
}
|
||||||
|
if (temp_change < -128) {
|
||||||
|
temp_change = -128;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data.temperature_change[my_position - 1] = (uint8_t)temp_change;
|
||||||
|
}
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
gCatena.SafePrintf("now going to sleep for 6 minutes...\n");
|
||||||
|
Serial.flush();
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL - 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_sensor_reading.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
last_sensor_reading.weight1 = weight1_current;
|
||||||
|
last_sensor_reading.weight2 = weight2_current;
|
||||||
|
last_sensor_reading.weight = weight_current;
|
||||||
|
last_sensor_reading.temperature = temp_current;
|
||||||
|
last_sensor_reading.humidity = humidity_current;
|
||||||
|
last_sensor_reading.pressure = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gCatena.SafePrintf("SendBuffer firstTime\n");
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gCatena.SafePrintf("SendBuffer not firstTime\n");
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("sendBufferDoneCB before TimedCallback\n");
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
gCatena.SafePrintf("sendBufferDoneCB after TimedCallback\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("settleDoneCb\n");
|
||||||
|
sleepDoneCb(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receiveMessage(void *pContext, uint8_t port, const uint8_t *pMessage, size_t nMessage)
|
||||||
|
{
|
||||||
|
unsigned txCycle;
|
||||||
|
unsigned txCount;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("receiveMessage was called!!!\n");
|
||||||
|
|
||||||
|
if (! (port == 1 && 2 <= nMessage && nMessage <= 3))
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("invalid message port(%02x)/length(%zx)\n",
|
||||||
|
port, nMessage
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
txCycle = (pMessage[0] << 8) | pMessage[1];
|
||||||
|
|
||||||
|
if (txCycle < CATCFG_T_MIN || txCycle > CATCFG_T_MAX)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("tx cycle time out of range: %u\n", txCycle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte [2], if present, is the repeat count.
|
||||||
|
// explicitly sending zero causes it to stick.
|
||||||
|
txCount = CATCFG_INTERVAL_COUNT;
|
||||||
|
if (nMessage >= 3)
|
||||||
|
{
|
||||||
|
txCount = pMessage[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we print out the received message...
|
||||||
|
gCatena.SafePrintf("Received Data (Payload): \n");
|
||||||
|
for (byte i = 0; i < nMessage; i++) {
|
||||||
|
gCatena.SafePrintf("%c", pMessage[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
setTxCycleTime(txCycle, txCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount)
|
||||||
|
{
|
||||||
|
if (txCount > 0)
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds for %u messages\n",
|
||||||
|
txCycle, txCount
|
||||||
|
);
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds indefinitely\n",
|
||||||
|
txCycle
|
||||||
|
);
|
||||||
|
|
||||||
|
gTxCycle = txCycle;
|
||||||
|
gTxCycleCount = txCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process "application hello" -- args are ignored */
|
||||||
|
// argv[0] is "hello"
|
||||||
|
// argv[1..argc-1] are the (ignored) arguments
|
||||||
|
cCommandStream::CommandStatus cmdHello(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("Hello, world!\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetCalibrationSettings(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"cal_w1_0\": \"%d\",\n", config_data.cal_w1_0);
|
||||||
|
pThis->printf(" \"cal_w2_0\": \"%d\",\n", config_data.cal_w2_0);
|
||||||
|
pThis->printf(" \"cal_w1_factor\": \"%d.%03d\n", (int)config_data.cal_w1_factor, (int)abs(config_data.cal_w1_factor * 1000) % 1000);
|
||||||
|
pThis->printf(" \"cal_w2_factor\": \"%d.%03d\n", (int)config_data.cal_w2_factor, (int)abs(config_data.cal_w2_factor * 1000) % 1000);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetSensorReadings(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"weight\": \"%d\",\n", last_sensor_reading.weight);
|
||||||
|
pThis->printf(" \"weight1_raw\": \"%d\",\n", last_sensor_reading.weight1);
|
||||||
|
pThis->printf(" \"weight2_raw\": \"%d\",\n", last_sensor_reading.weight2);
|
||||||
|
pThis->printf(" \"temperature\": \"%d\",\n", last_sensor_reading.temperature);
|
||||||
|
pThis->printf(" \"humidity\": \"%d\",\n", last_sensor_reading.humidity);
|
||||||
|
pThis->printf(" \"pressure\": \"%d\",\n", last_sensor_reading.pressure);
|
||||||
|
pThis->printf(" \"batt\": \"%d\",\n", last_sensor_reading.vbat);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale1\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale2\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
config_data.cal_w1_0 = last_sensor_reading.weight1;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
config_data.cal_w2_0 = last_sensor_reading.weight2;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
|
||||||
|
String w1_gramm(argv[1]);
|
||||||
|
config_data.cal_w1_factor = (((float)last_sensor_reading.weight1 - config_data.cal_w1_0) / w1_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
|
||||||
|
String w2_gramm(argv[1]);
|
||||||
|
config_data.cal_w2_factor = (((float)last_sensor_reading.weight2 - config_data.cal_w2_0) / w2_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,988 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
CATCFG_T_CYCLE_INITIAL = 30, // every 30 seconds initially
|
||||||
|
CATCFG_INTERVAL_COUNT_INITIAL = 30, // repeat for 15 minutes
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
CATCFG_T_MIN = CATCFG_T_OVERHEAD,
|
||||||
|
CATCFG_T_MAX = CATCFG_T_CYCLE < 60 * 60 ? 60 * 60 : CATCFG_T_CYCLE, // normally one hour max.
|
||||||
|
CATCFG_INTERVAL_COUNT = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// the cycle time to use
|
||||||
|
unsigned gTxCycle;
|
||||||
|
// remaining before we reset to default
|
||||||
|
unsigned gTxCycleCount;
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
static Arduino_LoRaWAN::ReceivePortBufferCbFn receiveMessage;
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount);
|
||||||
|
|
||||||
|
// Additional Commands
|
||||||
|
// forward reference to the command function
|
||||||
|
cCommandStream::CommandFn cmdHello;
|
||||||
|
cCommandStream::CommandFn cmdGetCalibrationSettings;
|
||||||
|
cCommandStream::CommandFn cmdGetSensorReadings;
|
||||||
|
cCommandStream::CommandFn cmdGetScale1;
|
||||||
|
cCommandStream::CommandFn cmdGetScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale2;
|
||||||
|
|
||||||
|
// the individual commmands are put in this table
|
||||||
|
static const cCommandStream::cEntry sMyExtraCommmands[] =
|
||||||
|
{
|
||||||
|
{ "hello", cmdHello },
|
||||||
|
{ "get_calibration_settings", cmdGetCalibrationSettings },
|
||||||
|
{ "get_sensor_readings", cmdGetSensorReadings },
|
||||||
|
{ "calibrate_zero_scale1", cmdCalibrateZeroScale1 },
|
||||||
|
{ "calibrate_zero_scale2", cmdCalibrateZeroScale2 },
|
||||||
|
{ "calibrate_scale1", cmdCalibrateScale1 },
|
||||||
|
{ "calibrate_scale2", cmdCalibrateScale2 },
|
||||||
|
// other commands go here....
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a top-level structure wraps the above and connects to the system table */
|
||||||
|
/* it optionally includes a "first word" so you can for sure avoid name clashes */
|
||||||
|
static cCommandStream::cDispatch
|
||||||
|
sMyExtraCommands_top(
|
||||||
|
sMyExtraCommmands, /* this is the pointer to the table */
|
||||||
|
sizeof(sMyExtraCommmands), /* this is the size of the table */
|
||||||
|
"application" /* this is the "first word" for all the commands in this table*/
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
// must be 65 bytes long...
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
long cal_w2_0; // 4 Bytes, Wert Waegezelle 2 ohne Gewicht
|
||||||
|
float cal_w1_factor; // 4 Bytes,
|
||||||
|
float cal_w2_factor;
|
||||||
|
byte fill[123];
|
||||||
|
} __attribute__((packed)) CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur (Startwert) in 1/10 Grad Celsius
|
||||||
|
int8_t temperature_change[MAX_VALUES_TO_SEND - 1]; // Unterschied Temperatur seit letztem Messwert in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading; // Zeitunterschied letzte zu erste Messung (in Minuten)
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t vbat; // Batteriespannung (0: <= 2510mV, 70: 3000mV, 170: 3700mV, 255: >= 4295mV [1 Einheit => 7mV])
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} SENSOR_data;
|
||||||
|
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
SENSOR_data last_sensor_reading;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
// Use D10 to regulate power
|
||||||
|
pinMode(D10, OUTPUT);
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
//setup_scales();
|
||||||
|
|
||||||
|
/* for 4451, we need wider tolerances, it seems */
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
LMIC_setClockError(10 * 65536 / 100);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* add our application-specific commands */
|
||||||
|
gCatena.addCommands(
|
||||||
|
sMyExtraCommands_top,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
// read config_data from fram...
|
||||||
|
gCatena.SafePrintf("Reading Calibration Config from FRAM...\n");
|
||||||
|
gCatena.getFram()->getField(cFramStorage::kBme680Cal, (uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("cal_w1_0: %d\n", config_data.cal_w1_0);
|
||||||
|
gCatena.SafePrintf("cal_w2_0: %d\n", config_data.cal_w2_0);
|
||||||
|
gCatena.SafePrintf("cal_w1_factor: %d.%03d\n", (int)config_data.cal_w1_factor, (int)(config_data.cal_w1_factor * 1000) % 1000);
|
||||||
|
gCatena.SafePrintf("cal_w2_factor: %d.%03d\n", (int)config_data.cal_w2_factor, (int)(config_data.cal_w2_factor * 1000) % 1000);
|
||||||
|
gCatena.SafePrintf("Size of config_data: %d\n", sizeof(config_data));
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
//config_data.cal_w1_0 = 20000;
|
||||||
|
//config_data.cal_w2_0 = 20000;
|
||||||
|
//config_data.cal_w1_factor = 2.5;
|
||||||
|
//config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
|
||||||
|
// config_data speichern...
|
||||||
|
//gCatena.SafePrintf("Writing Calibration Config to FRAM...\n");
|
||||||
|
//gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SetReceiveBufferBufferCb(receiveMessage);
|
||||||
|
setTxCycleTime(CATCFG_T_CYCLE_INITIAL, CATCFG_INTERVAL_COUNT_INITIAL);
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Enable Power
|
||||||
|
digitalWrite(D10, HIGH);
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//LoadCell_1.power_down();
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(D12, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//LoadCell_2.power_down();
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.temperature = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
lora_data.temperature_change[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n", lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n", lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n", lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n", lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n", lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n", lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n", lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n", lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n", lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n", lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n", lora_data.temperature);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld", lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature_change\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND - 1; i++) {
|
||||||
|
gCatena.SafePrintf("%d", lora_data.temperature_change[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetVBatValue(int millivolts)
|
||||||
|
{
|
||||||
|
uint8_t res;
|
||||||
|
if (millivolts <= 2510) {
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
} else if (millivolts >= 4295) {
|
||||||
|
res = 255;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res = (millivolts - 2510) / 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime, bool readOnly)
|
||||||
|
{
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
int16_t temp_change;
|
||||||
|
int32_t weight_current32;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int16_t)((m.Temperature) * 10);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n", pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
// Setup Scales
|
||||||
|
setup_scales();
|
||||||
|
|
||||||
|
// Read Scales
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
gCatena.SafePrintf("Load_cell 1 weight1_current: %ld\n", weight1_current);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
//LoadCell_1.power_down();
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_2.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
gCatena.SafePrintf("Load_cell 2 weight2_current: %ld\n", weight2_current);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
//LoadCell_2.power_down();
|
||||||
|
|
||||||
|
// Disable Power
|
||||||
|
digitalWrite(D10, LOW);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current32 = (int32_t)((((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor)) / 5.0);
|
||||||
|
if (weight_current32 < 0) {
|
||||||
|
weight_current32 = 0;
|
||||||
|
} else if (weight_current32 > UINT16_MAX) {
|
||||||
|
weight_current32 = UINT16_MAX;
|
||||||
|
}
|
||||||
|
weight_current = (uint16_t)weight_current32;
|
||||||
|
|
||||||
|
if (not(readOnly)) {
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
temp_last = lora_data.temperature;
|
||||||
|
|
||||||
|
for (int i = 0; i < my_position; i++) {
|
||||||
|
temp_last = temp_last + lora_data.temperature_change[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
if (my_position == 0) {
|
||||||
|
lora_data.temperature = temp_current;
|
||||||
|
} else {
|
||||||
|
temp_change = temp_current - temp_last;
|
||||||
|
if (temp_change > 127) {
|
||||||
|
temp_change = 127;
|
||||||
|
}
|
||||||
|
if (temp_change < -128) {
|
||||||
|
temp_change = -128;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data.temperature_change[my_position - 1] = (uint8_t)temp_change;
|
||||||
|
}
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
gCatena.SafePrintf("now going to sleep for 6 minutes...\n");
|
||||||
|
Serial.flush();
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
if (!fUsbPower) {
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL - 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_sensor_reading.vbat = GetVBatValue((int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
last_sensor_reading.weight1 = weight1_current;
|
||||||
|
last_sensor_reading.weight2 = weight2_current;
|
||||||
|
last_sensor_reading.weight = weight_current;
|
||||||
|
last_sensor_reading.temperature = temp_current;
|
||||||
|
last_sensor_reading.humidity = humidity_current;
|
||||||
|
last_sensor_reading.pressure = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gCatena.SafePrintf("SendBuffer firstTime\n");
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gCatena.SafePrintf("SendBuffer not firstTime\n");
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("sendBufferDoneCB before TimedCallback\n");
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
gCatena.SafePrintf("sendBufferDoneCB after TimedCallback\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("settleDoneCb\n");
|
||||||
|
sleepDoneCb(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receiveMessage(void *pContext, uint8_t port, const uint8_t *pMessage, size_t nMessage)
|
||||||
|
{
|
||||||
|
unsigned txCycle;
|
||||||
|
unsigned txCount;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("receiveMessage was called!!!\n");
|
||||||
|
|
||||||
|
if (! (port == 1 && 2 <= nMessage && nMessage <= 3))
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("invalid message port(%02x)/length(%zx)\n",
|
||||||
|
port, nMessage
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
txCycle = (pMessage[0] << 8) | pMessage[1];
|
||||||
|
|
||||||
|
if (txCycle < CATCFG_T_MIN || txCycle > CATCFG_T_MAX)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("tx cycle time out of range: %u\n", txCycle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte [2], if present, is the repeat count.
|
||||||
|
// explicitly sending zero causes it to stick.
|
||||||
|
txCount = CATCFG_INTERVAL_COUNT;
|
||||||
|
if (nMessage >= 3)
|
||||||
|
{
|
||||||
|
txCount = pMessage[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we print out the received message...
|
||||||
|
gCatena.SafePrintf("Received Data (Payload): \n");
|
||||||
|
for (byte i = 0; i < nMessage; i++) {
|
||||||
|
gCatena.SafePrintf("%c", pMessage[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
setTxCycleTime(txCycle, txCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount)
|
||||||
|
{
|
||||||
|
if (txCount > 0)
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds for %u messages\n",
|
||||||
|
txCycle, txCount
|
||||||
|
);
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds indefinitely\n",
|
||||||
|
txCycle
|
||||||
|
);
|
||||||
|
|
||||||
|
gTxCycle = txCycle;
|
||||||
|
gTxCycleCount = txCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process "application hello" -- args are ignored */
|
||||||
|
// argv[0] is "hello"
|
||||||
|
// argv[1..argc-1] are the (ignored) arguments
|
||||||
|
cCommandStream::CommandStatus cmdHello(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("Hello, world!\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetCalibrationSettings(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"cal_w1_0\": \"%d\",\n", config_data.cal_w1_0);
|
||||||
|
pThis->printf(" \"cal_w2_0\": \"%d\",\n", config_data.cal_w2_0);
|
||||||
|
pThis->printf(" \"cal_w1_factor\": \"%d.%03d\n", (int)config_data.cal_w1_factor, (int)abs(config_data.cal_w1_factor * 1000) % 1000);
|
||||||
|
pThis->printf(" \"cal_w2_factor\": \"%d.%03d\n", (int)config_data.cal_w2_factor, (int)abs(config_data.cal_w2_factor * 1000) % 1000);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetSensorReadings(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"weight\": \"%d\",\n", last_sensor_reading.weight);
|
||||||
|
pThis->printf(" \"weight1_raw\": \"%d\",\n", last_sensor_reading.weight1);
|
||||||
|
pThis->printf(" \"weight2_raw\": \"%d\",\n", last_sensor_reading.weight2);
|
||||||
|
pThis->printf(" \"temperature\": \"%d\",\n", last_sensor_reading.temperature);
|
||||||
|
pThis->printf(" \"humidity\": \"%d\",\n", last_sensor_reading.humidity);
|
||||||
|
pThis->printf(" \"pressure\": \"%d\",\n", last_sensor_reading.pressure);
|
||||||
|
pThis->printf(" \"batt\": \"%d\",\n", last_sensor_reading.vbat);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale1\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale2\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
config_data.cal_w1_0 = last_sensor_reading.weight1;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
config_data.cal_w2_0 = last_sensor_reading.weight2;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale1(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
|
||||||
|
String w1_gramm(argv[1]);
|
||||||
|
config_data.cal_w1_factor = (((float)last_sensor_reading.weight1 - config_data.cal_w1_0) / w1_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("last_sensor_reading.weight1: %ld\n", last_sensor_reading.weight1);
|
||||||
|
gCatena.SafePrintf("config_data.cal_w1_0: %ld\n", config_data.cal_w1_0);
|
||||||
|
gCatena.SafePrintf("w1_gramm: %s\n", w1_gramm);
|
||||||
|
gCatena.SafePrintf("w1_gramm (float): %d\n", (int)w1_gramm.toFloat());
|
||||||
|
gCatena.SafePrintf("config_data.cal_w1_factor: %d\n", (int)config_data.cal_w1_factor);
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale2(cCommandStream *pThis, void *pContext, int argc, char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false, true);
|
||||||
|
|
||||||
|
String w2_gramm(argv[1]);
|
||||||
|
config_data.cal_w2_factor = (((float)last_sensor_reading.weight2 - config_data.cal_w2_0) / w2_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,850 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
CATCFG_T_CYCLE_INITIAL = 30, // every 30 seconds initially
|
||||||
|
CATCFG_INTERVAL_COUNT_INITIAL = 30, // repeat for 15 minutes
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
CATCFG_T_MIN = CATCFG_T_OVERHEAD,
|
||||||
|
CATCFG_T_MAX = CATCFG_T_CYCLE < 60 * 60 ? 60 * 60 : CATCFG_T_CYCLE, // normally one hour max.
|
||||||
|
CATCFG_INTERVAL_COUNT = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// the cycle time to use
|
||||||
|
unsigned gTxCycle;
|
||||||
|
// remaining before we reset to default
|
||||||
|
unsigned gTxCycleCount;
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
static Arduino_LoRaWAN::ReceivePortBufferCbFn receiveMessage;
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
// must be 65 bytes long...
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
long cal_w2_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
float cal_w1_factor; // 4 Bytes,
|
||||||
|
float cal_w2_factor;
|
||||||
|
byte fill[49];
|
||||||
|
} __attribute__((packed)) CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur (Startwert) in 1/10 Grad Celsius
|
||||||
|
int8_t temperature_change[MAX_VALUES_TO_SEND - 1]; // Unterschied Temperatur seit letztem Messwert in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading; // Zeitunterschied letzte zu erste Messung (in Minuten)
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
|
||||||
|
/* for 4451, we need wider tolerances, it seems */
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
LMIC_setClockError(10 * 65536 / 100);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// read config_data from fram...
|
||||||
|
gCatena.SafePrintf("Reading Calibration Config from FRAM...\n");
|
||||||
|
gCatena.getFram()->getField(cFramStorage::kBme680Cal, (uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("cal_w1_0: %d\n",config_data.cal_w1_0);
|
||||||
|
gCatena.SafePrintf("cal_w2_0: %d\n",config_data.cal_w2_0);
|
||||||
|
gCatena.SafePrintf("cal_w1_factor: %d.%03d\n",(int)config_data.cal_w1_factor,(int)(config_data.cal_w1_factor*1000)%1000);
|
||||||
|
gCatena.SafePrintf("cal_w2_factor: %d.%03d\n",(int)config_data.cal_w2_factor,(int)(config_data.cal_w2_factor*1000)%1000);
|
||||||
|
gCatena.SafePrintf("Size of config_data: %d\n",sizeof(config_data));
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
//config_data.cal_w1_0 = 20000;
|
||||||
|
//config_data.cal_w2_0 = 20000;
|
||||||
|
//config_data.cal_w1_factor = 2.5;
|
||||||
|
//config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
|
||||||
|
// config_data speichern...
|
||||||
|
gCatena.SafePrintf("Writing Calibration Config to FRAM...\n");
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SetReceiveBufferBufferCb(receiveMessage);
|
||||||
|
setTxCycleTime(CATCFG_T_CYCLE_INITIAL, CATCFG_INTERVAL_COUNT_INITIAL);
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
//LoadCell_1.begin(A3, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
//LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.temperature = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
if (i < (MAX_VALUES_TO_SEND -1)) {
|
||||||
|
lora_data.temperature_change[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data.temperature);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature_change\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND - 1; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature_change[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
int16_t temp_change;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int16_t)((m.Temperature) * 10);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
temp_last = lora_data.temperature;
|
||||||
|
|
||||||
|
for (int i = 0; i < my_position; i++) {
|
||||||
|
temp_last = temp_last + lora_data.temperature_change[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
if (my_position == 0) {
|
||||||
|
lora_data.temperature = temp_current;
|
||||||
|
} else {
|
||||||
|
temp_change = temp_current - temp_last;
|
||||||
|
if (temp_change > 127) {
|
||||||
|
temp_change = 127;
|
||||||
|
}
|
||||||
|
if (temp_change < -128) {
|
||||||
|
temp_change = -128;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data.temperature_change[my_position - 1] = (uint8_t)temp_change;
|
||||||
|
}
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receiveMessage(void *pContext, uint8_t port, const uint8_t *pMessage, size_t nMessage)
|
||||||
|
{
|
||||||
|
unsigned txCycle;
|
||||||
|
unsigned txCount;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("receiveMessage was called!!!\n");
|
||||||
|
|
||||||
|
if (! (port == 1 && 2 <= nMessage && nMessage <= 3))
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("invalid message port(%02x)/length(%zx)\n",
|
||||||
|
port, nMessage
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
txCycle = (pMessage[0] << 8) | pMessage[1];
|
||||||
|
|
||||||
|
if (txCycle < CATCFG_T_MIN || txCycle > CATCFG_T_MAX)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("tx cycle time out of range: %u\n", txCycle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte [2], if present, is the repeat count.
|
||||||
|
// explicitly sending zero causes it to stick.
|
||||||
|
txCount = CATCFG_INTERVAL_COUNT;
|
||||||
|
if (nMessage >= 3)
|
||||||
|
{
|
||||||
|
txCount = pMessage[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we print out the received message...
|
||||||
|
gCatena.SafePrintf("Received Data (Payload): \n");
|
||||||
|
for (byte i = 0; i < nMessage; i++) {
|
||||||
|
gCatena.SafePrintf("%c", pMessage[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
setTxCycleTime(txCycle, txCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTxCycleTime(unsigned txCycle, unsigned txCount)
|
||||||
|
{
|
||||||
|
if (txCount > 0)
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds for %u messages\n",
|
||||||
|
txCycle, txCount
|
||||||
|
);
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"message cycle time %u seconds indefinitely\n",
|
||||||
|
txCycle
|
||||||
|
);
|
||||||
|
|
||||||
|
gTxCycle = txCycle;
|
||||||
|
gTxCycleCount = txCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,718 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0;
|
||||||
|
long cal_w2_0;
|
||||||
|
float cal_w1_factor;
|
||||||
|
float cal_w2_factor;
|
||||||
|
} CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading;
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
config_data.cal_w1_0 = 20000;
|
||||||
|
config_data.cal_w2_0 = 20000;
|
||||||
|
config_data.cal_w1_factor = 2.5;
|
||||||
|
config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
uint8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
uint8_t temp_last;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (uint8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,649 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 4;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Versionierung des Paketformats
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Zehntels-Prozent
|
||||||
|
uint8_t pressure; // Luftdruck in XXXX
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der Messung in Sekunden, erster Wert ist 0
|
||||||
|
int16_t weight_raw1[MAX_VALUES_TO_SEND]; // Reading (raw) der ersten Waegzelle
|
||||||
|
int16_t weight_raw2[MAX_VALUES_TO_SEND]; // Reading (raw) der zweiten Waegzelle
|
||||||
|
int16_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/10 Grad Celsius
|
||||||
|
} LORA_data;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position >= MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.humidity = 0;
|
||||||
|
lora_data.pressure = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
lora_data.weight_raw1[i] = 0;
|
||||||
|
lora_data.weight_raw2[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%i\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%i\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%i\",\n",lora_data.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%i\",\n",lora_data.pressure);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%i",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight_raw1\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%i",lora_data.weight_raw1[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight_raw2\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%i",lora_data.weight_raw2[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%i",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int16_t w1_current;
|
||||||
|
int16_t w2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
uint8_t humidity_last;
|
||||||
|
uint8_t pressure_last;
|
||||||
|
int16_t w1_last;
|
||||||
|
int16_t w2_last;
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = m.Temperature;
|
||||||
|
humidity_current = m.Humidity;
|
||||||
|
pressure_current = m.Pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
w1_current = w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
w2_current = w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last = lora_data.temperature[my_position - 1];
|
||||||
|
w1_last = lora_data.weight_raw1[my_position - 1];
|
||||||
|
w2_last = lora_data.weight_raw2[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 10 || abs(w1_current - w1_last) > 50 || abs(w2_current - w2_last) > 50) {
|
||||||
|
lora_data.vbat = (vBat * 1000 / 20);
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position] = int((millis() - timer_pos0) / 1000);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
lora_data.weight_raw1[my_position] = w1_current;
|
||||||
|
lora_data.weight_raw2[my_position] = w2_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity = humidity_current;
|
||||||
|
lora_data.pressure = humidity_current;
|
||||||
|
|
||||||
|
ShowLORAData();
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(void)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,656 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 6;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 80000;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0;
|
||||||
|
long cal_w2_0;
|
||||||
|
float cal_w1_factor;
|
||||||
|
float cal_w2_factor;
|
||||||
|
} FRAM_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Versionierung des Paketformats
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t pressure; // Luftdruck in Pascal (0 entspricht 80000 Pa)
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der weiteren Messung in Sekunden seit Start
|
||||||
|
int16_t weight[MAX_VALUES_TO_SEND]; // Gewicht in 10-Gramm, Addition beider Waegzellen
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
} LORA_data;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
FRAM_data fram_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
// aktuell noch als Konstanten...
|
||||||
|
fram_data.cal_w1_0 = -10000;
|
||||||
|
fram_data.cal_w2_0 = -10000;
|
||||||
|
fram_data.cal_w1_factor = 1;
|
||||||
|
fram_data.cal_w2_factor = 1;
|
||||||
|
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position > MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.humidity = 0;
|
||||||
|
lora_data.pressure = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(void)
|
||||||
|
{
|
||||||
|
char str[10];
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%d\",\n",lora_data.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%d\",\n",lora_data.pressure);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%u",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
int16_t pressure_current;
|
||||||
|
int32_t weight_current;
|
||||||
|
int32_t w1_current;
|
||||||
|
int32_t w2_current;
|
||||||
|
int8_t temp_last;
|
||||||
|
int32_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint16_t)(m.Pressure - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
w1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
w2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Calculate Weight
|
||||||
|
weight_current = (((w1_current - fram_data.cal_w1_0) / fram_data.cal_w1_factor) + ((w2_current - fram_data.cal_w2_0) / fram_data.cal_w2_factor));
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist, oder es die erste Messung ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 3 || abs(weight_current - weight_last) > 50) {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position] = (uint8_t)((millis() - timer_pos0) / 1000);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
lora_data.humidity = humidity_current;
|
||||||
|
lora_data.pressure = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData();
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(void)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,668 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 3;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 80000;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Versionierung des Paketformats
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
int16_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Pascal (0 entspricht 80000 Pa)
|
||||||
|
int32_t weight1[MAX_VALUES_TO_SEND]; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2[MAX_VALUES_TO_SEND]; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t reading_offset[MAX_VALUES_TO_SEND - 1]; // Zeit der weiteren Messungen in Sekunden seit Start
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position >= MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
}
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight1[i] = 0;
|
||||||
|
lora_data.weight2[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < (MAX_VALUES_TO_SEND - 1); i++) {
|
||||||
|
gCatena.SafePrintf("%u",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight1\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight1[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight2\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight2[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
int16_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int8_t temp_last;
|
||||||
|
int32_t weight1_last;
|
||||||
|
int32_t weight2_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (int16_t)(m.Pressure - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight1_last = lora_data.weight1[my_position - 1];
|
||||||
|
weight2_last = lora_data.weight2[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist, oder es die erste Messung ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 3 || abs(weight1_current - weight1_last) > 500 || abs(weight2_current - weight2_last) > 500) {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight1[my_position] = weight1_current;
|
||||||
|
lora_data.weight2[my_position] = weight2_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position - 1] = (uint16_t)((millis() - timer_pos0) / 1000);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData();
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink();
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(void)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,667 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 3;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 80000;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Versionierung des Paketformats
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
int16_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Pascal (0 entspricht 80000 Pa)
|
||||||
|
int32_t weight1[MAX_VALUES_TO_SEND]; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2[MAX_VALUES_TO_SEND]; // Waegezelle 2, Raw Value
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der weiteren Messungen in Minuten seit Start, letzter Wert: Offset beim Senden des Pakets
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position >= MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight1[i] = 0;
|
||||||
|
lora_data.weight2[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < (MAX_VALUES_TO_SEND); i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight1\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight1[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight2\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight2[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
int16_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int8_t temp_last;
|
||||||
|
int32_t weight1_last;
|
||||||
|
int32_t weight2_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (int16_t)(m.Pressure - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight1_last = lora_data.weight1[my_position - 1];
|
||||||
|
weight2_last = lora_data.weight2[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist, oder es die erste Messung ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 3 || abs(weight1_current - weight1_last) > 500 || abs(weight2_current - weight2_last) > 500) {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight1[my_position] = weight1_current;
|
||||||
|
lora_data.weight2[my_position] = weight2_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position - 1] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData();
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
lora_data.reading_offset[my_position] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink();
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(void)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,923 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
//CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE = 10, // every 10 seconds
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
CATCFG_T_CYCLE_INITIAL = 30, // every 30 seconds initially
|
||||||
|
CATCFG_INTERVAL_COUNT_INITIAL = 30, // repeat for 15 minutes
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
CATCFG_T_MIN = CATCFG_T_OVERHEAD,
|
||||||
|
CATCFG_T_MAX = CATCFG_T_CYCLE < 60 * 60 ? 60 * 60 : CATCFG_T_CYCLE, // normally one hour max.
|
||||||
|
CATCFG_INTERVAL_COUNT = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// the cycle time to use
|
||||||
|
unsigned gTxCycle;
|
||||||
|
// remaining before we reset to default
|
||||||
|
unsigned gTxCycleCount;
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
// Additional Commands
|
||||||
|
// forward reference to the command function
|
||||||
|
cCommandStream::CommandFn cmdHello;
|
||||||
|
cCommandStream::CommandFn cmdGetCalibrationSettings;
|
||||||
|
cCommandStream::CommandFn cmdGetSensorReadings;
|
||||||
|
cCommandStream::CommandFn cmdGetScale1;
|
||||||
|
cCommandStream::CommandFn cmdGetScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateZeroScale2;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale1;
|
||||||
|
cCommandStream::CommandFn cmdCalibrateScale2;
|
||||||
|
|
||||||
|
// the individual commmands are put in this table
|
||||||
|
static const cCommandStream::cEntry sMyExtraCommmands[] =
|
||||||
|
{
|
||||||
|
{ "hello", cmdHello },
|
||||||
|
{ "get_calibration_settings", cmdGetCalibrationSettings },
|
||||||
|
{ "get_sensor_readings", cmdGetSensorReadings },
|
||||||
|
{ "calibrate_zero_scale1", cmdCalibrateZeroScale1 },
|
||||||
|
{ "calibrate_zero_scale2", cmdCalibrateZeroScale2 },
|
||||||
|
{ "calibrate_scale1", cmdCalibrateScale1 },
|
||||||
|
{ "calibrate_scale2", cmdCalibrateScale2 },
|
||||||
|
// other commands go here....
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a top-level structure wraps the above and connects to the system table */
|
||||||
|
/* it optionally includes a "first word" so you can for sure avoid name clashes */
|
||||||
|
static cCommandStream::cDispatch
|
||||||
|
sMyExtraCommands_top(
|
||||||
|
sMyExtraCommmands, /* this is the pointer to the table */
|
||||||
|
sizeof(sMyExtraCommmands), /* this is the size of the table */
|
||||||
|
"application" /* this is the "first word" for all the commands in this table*/
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
// must be 65 bytes long...
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
long cal_w2_0; // 4 Bytes, Wert Waegezelle 2 ohne Gewicht
|
||||||
|
float cal_w1_factor; // 4 Bytes,
|
||||||
|
float cal_w2_factor;
|
||||||
|
byte fill[49];
|
||||||
|
} __attribute__((packed)) CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur (Startwert) in 1/10 Grad Celsius
|
||||||
|
int8_t temperature_change[MAX_VALUES_TO_SEND - 1]; // Unterschied Temperatur seit letztem Messwert in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading; // Zeitunterschied letzte zu erste Messung (in Minuten)
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} SENSOR_data;
|
||||||
|
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
SENSOR_data last_sensor_reading;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
|
||||||
|
/* for 4451, we need wider tolerances, it seems */
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
LMIC_setClockError(10 * 65536 / 100);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// prepare external Power
|
||||||
|
pinMode(D10, OUTPUT);
|
||||||
|
digitalWrite(D10, HIGH);
|
||||||
|
|
||||||
|
/* add our application-specific commands */
|
||||||
|
gCatena.addCommands(
|
||||||
|
sMyExtraCommands_top,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
// read config_data from fram...
|
||||||
|
//gCatena.SafePrintf("Reading Calibration Config from FRAM...\n");
|
||||||
|
gCatena.getFram()->getField(cFramStorage::kBme680Cal, (uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
//gCatena.SafePrintf("cal_w1_0: %d\n",config_data.cal_w1_0);
|
||||||
|
//gCatena.SafePrintf("cal_w2_0: %d\n",config_data.cal_w2_0);
|
||||||
|
//gCatena.SafePrintf("cal_w1_factor: %d.%03d\n",(int)config_data.cal_w1_factor,(int)(config_data.cal_w1_factor*1000)%1000);
|
||||||
|
//gCatena.SafePrintf("cal_w2_factor: %d.%03d\n",(int)config_data.cal_w2_factor,(int)(config_data.cal_w2_factor*1000)%1000);
|
||||||
|
//gCatena.SafePrintf("Size of config_data: %d\n",sizeof(config_data));
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
//config_data.cal_w1_0 = 20000;
|
||||||
|
//config_data.cal_w2_0 = 20000;
|
||||||
|
//config_data.cal_w1_factor = 2.5;
|
||||||
|
//config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
|
||||||
|
// config_data speichern...
|
||||||
|
//gCatena.SafePrintf("Writing Calibration Config to FRAM...\n");
|
||||||
|
//gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//gCatena.SafePrintf("\n");
|
||||||
|
//gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
//gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
//gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
// gLoRaWAN.GetNetworkName(),
|
||||||
|
// gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
//gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
//gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
//gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
//gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
//gCatena.SafePrintf(
|
||||||
|
// "CPU Unique ID: %s\n",
|
||||||
|
// gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
//gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
//gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::On);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
//gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only read vBus once, as there was a read error after deep sleep...
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(D12, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.temperature = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
if (i < (MAX_VALUES_TO_SEND -1)) {
|
||||||
|
lora_data.temperature_change[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data.temperature);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature_change\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND - 1; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature_change[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime, bool readOnly)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("start ReadSensors\n");
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
int16_t temp_change;
|
||||||
|
int32_t weight_current32;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int16_t)((m.Temperature) * 10);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
//float vBus = gCatena.ReadVbus();
|
||||||
|
//gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
//fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
// Read Scales
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_2.power_up();
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
LoadCell_2.power_down();
|
||||||
|
|
||||||
|
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current32 = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
if (weight_current32 < 0) {
|
||||||
|
weight_current32 = 0;
|
||||||
|
} else if (weight_current32 > UINT16_MAX) {
|
||||||
|
weight_current32 = UINT16_MAX;
|
||||||
|
}
|
||||||
|
weight_current = (uint16_t)weight_current32;
|
||||||
|
|
||||||
|
if (not(readOnly)) {
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
temp_last = lora_data.temperature;
|
||||||
|
|
||||||
|
for (int i = 0; i < my_position; i++) {
|
||||||
|
temp_last = temp_last + lora_data.temperature_change[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
if (my_position == 0) {
|
||||||
|
lora_data.temperature = temp_current;
|
||||||
|
} else {
|
||||||
|
temp_change = temp_current - temp_last;
|
||||||
|
if (temp_change > 127) {
|
||||||
|
temp_change = 127;
|
||||||
|
}
|
||||||
|
if (temp_change < -128) {
|
||||||
|
temp_change = -128;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data.temperature_change[my_position - 1] = (uint8_t)temp_change;
|
||||||
|
}
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
Serial.flush();
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
LoadCell_2.power_down();
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//gCatena.SafePrintf("set last_sensor_reading fields...\n");
|
||||||
|
last_sensor_reading.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
last_sensor_reading.weight1 = weight1_current;
|
||||||
|
last_sensor_reading.weight2 = weight2_current;
|
||||||
|
last_sensor_reading.weight = weight_current;
|
||||||
|
last_sensor_reading.temperature = temp_current;
|
||||||
|
last_sensor_reading.humidity = humidity_current;
|
||||||
|
last_sensor_reading.pressure = pressure_current;
|
||||||
|
gCatena.SafePrintf("completed ReadSensors\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start startSendingUplink\n");
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
//gCatena.SafePrintf("completed startSendingUplink\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start sendBufferDoneCb\n");
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
//gCatena.SafePrintf("completed sendBufferDoneCb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start txFailedDoneCb\n");
|
||||||
|
//gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
//gCatena.SafePrintf("completed txFailedDoneCb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start settleDoneCb\n");
|
||||||
|
if (fUsbPower) {
|
||||||
|
//gCatena.SafePrintf("we are running on USB power, so we do not go to deep sleep...\n");
|
||||||
|
//gCatena.SafePrintf("calling os_setTimedCallback in settleDoneCb...Interval=%d\n",CATCFG_T_INTERVAL);
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime()+sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb
|
||||||
|
);
|
||||||
|
gCatena.SafePrintf("returning from settleDoneCb\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok..., now it's time for a deep sleep */
|
||||||
|
|
||||||
|
|
||||||
|
Serial.flush();
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
LoadCell_2.power_down();
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
sleepDoneCb(pSendJob);
|
||||||
|
gCatena.SafePrintf("completed settleDoneCb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start sleepDoneCb\n");
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
//gCatena.SafePrintf("completed sleepDoneCb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
//gCatena.SafePrintf("start warmupDoneCb\n");
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
ReadSensors(false,false);
|
||||||
|
//gCatena.SafePrintf("completed warmupDoneCb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* process "application hello" -- args are ignored */
|
||||||
|
// argv[0] is "hello"
|
||||||
|
// argv[1..argc-1] are the (ignored) arguments
|
||||||
|
cCommandStream::CommandStatus cmdHello(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("Hello, world!\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetCalibrationSettings(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"cal_w1_0\": \"%d\",\n",config_data.cal_w1_0);
|
||||||
|
pThis->printf(" \"cal_w2_0\": \"%d\",\n",config_data.cal_w2_0);
|
||||||
|
pThis->printf(" \"cal_w1_factor\": \"%d.%03d\n",(int)config_data.cal_w1_factor,(int)abs(config_data.cal_w1_factor*1000)%1000);
|
||||||
|
pThis->printf(" \"cal_w2_factor\": \"%d.%03d\n",(int)config_data.cal_w2_factor,(int)abs(config_data.cal_w2_factor*1000)%1000);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetSensorReadings(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false,true);
|
||||||
|
pThis->printf("{\n");
|
||||||
|
pThis->printf(" \"weight\": \"%d\",\n",last_sensor_reading.weight);
|
||||||
|
pThis->printf(" \"weight1_raw\": \"%d\",\n",last_sensor_reading.weight1);
|
||||||
|
pThis->printf(" \"weight2_raw\": \"%d\",\n",last_sensor_reading.weight2);
|
||||||
|
pThis->printf(" \"temperature\": \"%d\",\n",last_sensor_reading.temperature);
|
||||||
|
pThis->printf(" \"humidity\": \"%d\",\n",last_sensor_reading.humidity);
|
||||||
|
pThis->printf(" \"pressure\": \"%d\",\n",last_sensor_reading.pressure);
|
||||||
|
pThis->printf(" \"batt\": \"%d\",\n", last_sensor_reading.vbat);
|
||||||
|
pThis->printf("}\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale1(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale1\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdGetScale2(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
pThis->printf("getscale2\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale1(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false,true);
|
||||||
|
config_data.cal_w1_0 = last_sensor_reading.weight1;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateZeroScale2(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false,true);
|
||||||
|
config_data.cal_w2_0 = last_sensor_reading.weight2;
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_zero_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale1(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false,true);
|
||||||
|
|
||||||
|
String w1_gramm(argv[1]);
|
||||||
|
config_data.cal_w1_factor = (((float)last_sensor_reading.weight1 - config_data.cal_w1_0)/ w1_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale1 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCommandStream::CommandStatus cmdCalibrateScale2(cCommandStream *pThis,void *pContext,int argc,char **argv)
|
||||||
|
{
|
||||||
|
ReadSensors(false,true);
|
||||||
|
|
||||||
|
String w2_gramm(argv[1]);
|
||||||
|
config_data.cal_w2_factor = (((float)last_sensor_reading.weight2 - config_data.cal_w2_0)/ w2_gramm.toFloat());
|
||||||
|
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
pThis->printf("{ \"msg\": \"calibrate_scale2 was successful\" }\n");
|
||||||
|
|
||||||
|
return cCommandStream::CommandStatus::kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,727 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 6;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0;
|
||||||
|
long cal_w2_0;
|
||||||
|
float cal_w1_factor;
|
||||||
|
float cal_w2_factor;
|
||||||
|
} CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der weiteren Messungen in Minuten seit Start, letzter Wert: Offset beim Senden des Pakets
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
config_data.cal_w1_0 = 20000;
|
||||||
|
config_data.cal_w2_0 = 20000;
|
||||||
|
config_data.cal_w1_factor = 2.5;
|
||||||
|
config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position >= MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < (MAX_VALUES_TO_SEND); i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
uint8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
uint8_t temp_last;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (uint8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist, oder es die erste Messung ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 3 || abs(weight_current - weight_last) > 10) {
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position - 1] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
lora_data.reading_offset[my_position] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,727 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 6;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0;
|
||||||
|
long cal_w2_0;
|
||||||
|
float cal_w1_factor;
|
||||||
|
float cal_w2_factor;
|
||||||
|
} CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature[MAX_VALUES_TO_SEND]; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t reading_offset[MAX_VALUES_TO_SEND]; // Zeit der weiteren Messungen in Minuten seit Start, letzter Wert: Offset beim Senden des Pakets
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
uint8_t temperature; // Temperatur in 1/2 Grad Celsius (0 => -40 C, 255 => 87.5 C)
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
config_data.cal_w1_0 = 20000;
|
||||||
|
config_data.cal_w2_0 = 20000;
|
||||||
|
config_data.cal_w1_factor = 2.5;
|
||||||
|
config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
LoadCell_1.begin(A3, A2);
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldDataBeSent(void)
|
||||||
|
{
|
||||||
|
bool res = (my_position >= MAX_VALUES_TO_SEND) ||
|
||||||
|
((millis() - timer_pos0) > 3600000);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.reading_offset[i] = 0;
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
lora_data.temperature[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"reading_offset\": [");
|
||||||
|
for (int i = 0; i < (MAX_VALUES_TO_SEND); i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.reading_offset[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
uint8_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
uint8_t temp_last;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (uint8_t)((m.Temperature + 40) * 2);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
if (my_position > 0) {
|
||||||
|
temp_last =lora_data.temperature[my_position -1];
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir registrieren die Werte nur, falls die Abweichung zur letzen Messung gross genug ist, oder es die erste Messung ist
|
||||||
|
if (my_position == 0 || abs(temp_current - temp_last) > 3 || abs(weight_current - weight_last) > 10) {
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
lora_data.temperature[my_position] = temp_current;
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
if (my_position > 0) {
|
||||||
|
lora_data.reading_offset[my_position - 1] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
} else {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("Too little difference, measurements are not stored...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
if (firstTime || ShouldDataBeSent()) {
|
||||||
|
lora_data.reading_offset[MAX_VALUES_TO_SEND - 1] = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,768 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
beescale_lora_mcci.ino
|
||||||
|
|
||||||
|
BeieliScale, see https://mini-beieli.ch
|
||||||
|
|
||||||
|
Joerg Lehmann, nbit Informatik GmbH
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Catena.h>
|
||||||
|
|
||||||
|
#include <Catena_Led.h>
|
||||||
|
#include <Catena_CommandStream.h>
|
||||||
|
#include <Catena_Mx25v8035f.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
#include <Arduino_LoRaWAN.h>
|
||||||
|
#include <lmic.h>
|
||||||
|
#include <hal/hal.h>
|
||||||
|
#include <mcciadk_baselib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <HX711.h>
|
||||||
|
|
||||||
|
using namespace McciCatena;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| MANIFEST CONSTANTS & TYPEDEFS
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
/* how long do we wait between transmissions? (in seconds) */
|
||||||
|
enum {
|
||||||
|
// set this to interval between transmissions, in seconds
|
||||||
|
// Actual time will be a little longer because have to
|
||||||
|
// add measurement and broadcast time, but we attempt
|
||||||
|
// to compensate for the gross effects below.
|
||||||
|
//CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE = 6 * 60, // every 6 minutes
|
||||||
|
CATCFG_T_CYCLE_TEST = 30, // every 10 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/* additional timing parameters; ususually you don't change these. */
|
||||||
|
enum {
|
||||||
|
CATCFG_T_WARMUP = 1,
|
||||||
|
CATCFG_T_SETTLE = 5,
|
||||||
|
CATCFG_T_OVERHEAD = (CATCFG_T_WARMUP + CATCFG_T_SETTLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t CATCFG_GetInterval(uint32_t tCycle)
|
||||||
|
{
|
||||||
|
return (tCycle < CATCFG_T_OVERHEAD)
|
||||||
|
? CATCFG_T_OVERHEAD
|
||||||
|
: tCycle - CATCFG_T_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CATCFG_T_INTERVAL = CATCFG_GetInterval(CATCFG_T_CYCLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_ONE_WIRE = A2, // XSDA1 == A2
|
||||||
|
PIN_SHT10_CLK = 8, // XSCL0 == D8
|
||||||
|
PIN_SHT10_DATA = 12, // XSDA0 == D12
|
||||||
|
};
|
||||||
|
|
||||||
|
// forwards
|
||||||
|
static void settleDoneCb(osjob_t* pSendJob);
|
||||||
|
static void warmupDoneCb(osjob_t* pSendJob);
|
||||||
|
static void txFailedDoneCb(osjob_t* pSendJob);
|
||||||
|
static void sleepDoneCb(osjob_t* pSendJob);
|
||||||
|
static Arduino_LoRaWAN::SendBufferCbFn sendBufferDoneCb;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| READ-ONLY DATA
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static const char sVersion[] = "0.1";
|
||||||
|
static const byte MAX_VALUES_TO_SEND = 8;
|
||||||
|
static const uint8_t LORA_DATA_VERSION = 1;
|
||||||
|
static const uint8_t LORA_DATA_VERSION_FIRST_PACKAGE = 128;
|
||||||
|
static const uint32_t PRESSURE_OFFSET = 825;
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| VARIABLES
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
// must be 65 bytes long...
|
||||||
|
typedef struct {
|
||||||
|
long cal_w1_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
long cal_w2_0; // 4 Bytes, Wert Waegezelle 1 ohne Gewicht
|
||||||
|
float cal_w1_factor; // 4 Bytes,
|
||||||
|
float cal_w2_factor;
|
||||||
|
byte fill[49];
|
||||||
|
} __attribute__((packed)) CONFIG_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity[MAX_VALUES_TO_SEND]; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur (Startwert) in 1/10 Grad Celsius
|
||||||
|
int8_t temperature_change[MAX_VALUES_TO_SEND - 1]; // Unterschied Temperatur seit letztem Messwert in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure[MAX_VALUES_TO_SEND]; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
uint16_t weight[MAX_VALUES_TO_SEND]; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
uint8_t offset_last_reading; // Zeitunterschied letzte zu erste Messung (in Minuten)
|
||||||
|
} __attribute__((packed)) LORA_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version; // Version
|
||||||
|
uint8_t vbat; // Batteriespannung (1 Einheit => 20 mV)
|
||||||
|
uint8_t humidity; // Luftfeuchtigkeit in Prozent
|
||||||
|
int16_t temperature; // Temperatur in 1/10 Grad Celsius
|
||||||
|
uint8_t pressure; // Luftdruck in Hekto-Pascal (0 entspricht 825 hPa)
|
||||||
|
int32_t weight1; // Waegezelle 1, Raw Value
|
||||||
|
int32_t weight2; // Waegezelle 2, Raw Value
|
||||||
|
uint16_t weight; // Waegezelle Gesamtgewicht, in 5g
|
||||||
|
} __attribute__((packed)) LORA_data_first;
|
||||||
|
|
||||||
|
byte my_position = 0; // what is our actual measurement, starts with 0
|
||||||
|
long timer_pos0;
|
||||||
|
|
||||||
|
// Global Variables
|
||||||
|
LORA_data lora_data;
|
||||||
|
LORA_data_first lora_data_first;
|
||||||
|
CONFIG_data config_data;
|
||||||
|
|
||||||
|
// generic timer
|
||||||
|
long t_cur;
|
||||||
|
|
||||||
|
// the primary object
|
||||||
|
Catena gCatena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LoRaWAN backhaul. Note that we use the
|
||||||
|
// Catena version so it can provide hardware-specific
|
||||||
|
// information to the base class.
|
||||||
|
//
|
||||||
|
Catena::LoRaWAN gLoRaWAN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the LED
|
||||||
|
//
|
||||||
|
StatusLed gLed(Catena::PIN_STATUS_LED);
|
||||||
|
|
||||||
|
// The temperature/humidity sensor
|
||||||
|
Adafruit_BME280 gBME280; // The default initalizer creates an I2C connection
|
||||||
|
bool fBme;
|
||||||
|
|
||||||
|
SPIClass gSPI2(
|
||||||
|
Catena::PIN_SPI2_MOSI,
|
||||||
|
Catena::PIN_SPI2_MISO,
|
||||||
|
Catena::PIN_SPI2_SCK);
|
||||||
|
|
||||||
|
// The flash
|
||||||
|
Catena_Mx25v8035f gFlash;
|
||||||
|
bool fFlash;
|
||||||
|
|
||||||
|
// Scales
|
||||||
|
HX711 LoadCell_1;
|
||||||
|
HX711 LoadCell_2;
|
||||||
|
|
||||||
|
// USB power
|
||||||
|
bool fUsbPower;
|
||||||
|
|
||||||
|
// have we printed the sleep info?
|
||||||
|
bool g_fPrintedSleeping = false;
|
||||||
|
|
||||||
|
// the job that's used to synchronize us with the LMIC code
|
||||||
|
static osjob_t sensorJob;
|
||||||
|
void sensorJob_cb(osjob_t* pJob);
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
gCatena.begin();
|
||||||
|
ClearLoraData();
|
||||||
|
|
||||||
|
setup_platform();
|
||||||
|
setup_bme280();
|
||||||
|
setup_scales();
|
||||||
|
setup_flash();
|
||||||
|
setup_uplink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_platform(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// read config_data from fram...
|
||||||
|
gCatena.SafePrintf("Reading Calibration Config from FRAM...\n");
|
||||||
|
gCatena.getFram()->getField(cFramStorage::kBme680Cal, (uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("cal_w1_0: %d\n",config_data.cal_w1_0);
|
||||||
|
gCatena.SafePrintf("cal_w2_0: %d\n",config_data.cal_w2_0);
|
||||||
|
gCatena.SafePrintf("cal_w1_factor: %d.%03d\n",(int)config_data.cal_w1_factor,(int)(config_data.cal_w1_factor*1000)%1000);
|
||||||
|
gCatena.SafePrintf("cal_w2_factor: %d.%03d\n",(int)config_data.cal_w2_factor,(int)(config_data.cal_w2_factor*1000)%1000);
|
||||||
|
gCatena.SafePrintf("Size of config_data: %d\n",sizeof(config_data));
|
||||||
|
|
||||||
|
// im Moment statisch...
|
||||||
|
//config_data.cal_w1_0 = 20000;
|
||||||
|
//config_data.cal_w2_0 = 20000;
|
||||||
|
//config_data.cal_w1_factor = 2.5;
|
||||||
|
//config_data.cal_w2_factor = 2.5;
|
||||||
|
|
||||||
|
|
||||||
|
// config_data speichern...
|
||||||
|
gCatena.SafePrintf("Writing Calibration Config to FRAM...\n");
|
||||||
|
gCatena.getFram()->saveField(cFramStorage::kBme680Cal, (const uint8_t *)&config_data, sizeof(config_data));
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
// if running unattended, don't wait for USB connect.
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended))) {
|
||||||
|
while (!Serial)
|
||||||
|
/* wait for USB attach */
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
gCatena.SafePrintf("-------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("BeieliScale Version %s.\n", sVersion);
|
||||||
|
{
|
||||||
|
char sRegion[16];
|
||||||
|
gCatena.SafePrintf("Target network: %s / %s\n",
|
||||||
|
gLoRaWAN.GetNetworkName(),
|
||||||
|
gLoRaWAN.GetRegionString(sRegion, sizeof(sRegion)));
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("Enter 'help' for a list of commands.\n");
|
||||||
|
|
||||||
|
#ifdef CATENA_CFG_SYSCLK
|
||||||
|
gCatena.SafePrintf("SYSCLK: %d MHz\n", CATENA_CFG_SYSCLK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USBCON
|
||||||
|
gCatena.SafePrintf("USB enabled\n");
|
||||||
|
#else
|
||||||
|
gCatena.SafePrintf("USB disabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Catena::UniqueID_string_t CpuIDstring;
|
||||||
|
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"CPU Unique ID: %s\n",
|
||||||
|
gCatena.GetUniqueIDstring(&CpuIDstring));
|
||||||
|
|
||||||
|
gCatena.SafePrintf("--------------------------------------------------------------------------------\n");
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
|
||||||
|
// set up the LED
|
||||||
|
gLed.begin();
|
||||||
|
gCatena.registerObject(&gLed);
|
||||||
|
gLed.Set(LedPattern::FastFlash);
|
||||||
|
|
||||||
|
// set up LoRaWAN
|
||||||
|
gCatena.SafePrintf("LoRaWAN init: ");
|
||||||
|
if (!gLoRaWAN.begin(&gCatena)) {
|
||||||
|
gCatena.SafePrintf("failed\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("succeeded\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.registerObject(&gLoRaWAN);
|
||||||
|
|
||||||
|
/* find the platform */
|
||||||
|
const Catena::EUI64_buffer_t* pSysEUI = gCatena.GetSysEUI();
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
|
const CATENA_PLATFORM* const pPlatform = gCatena.GetPlatform();
|
||||||
|
|
||||||
|
if (pPlatform) {
|
||||||
|
gCatena.SafePrintf("EUI64: ");
|
||||||
|
for (unsigned i = 0; i < sizeof(pSysEUI->b); ++i) {
|
||||||
|
gCatena.SafePrintf("%s%02x", i == 0 ? "" : "-", pSysEUI->b[i]);
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\n");
|
||||||
|
flags = gCatena.GetPlatformFlags();
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Platform Flags: %#010x\n",
|
||||||
|
flags);
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"Operating Flags: %#010x\n",
|
||||||
|
gCatena.GetOperatingFlags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gCatena.SafePrintf("**** no platform, check provisioning ****\n");
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_bme280(void)
|
||||||
|
{
|
||||||
|
if (gBME280.begin(BME280_ADDRESS, Adafruit_BME280::OPERATING_MODE::Sleep)) {
|
||||||
|
fBme = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fBme = false;
|
||||||
|
gCatena.SafePrintf("No BME280 found: check wiring\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_scales(void)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("Setup Scales...\n");
|
||||||
|
|
||||||
|
// Initialize library with data output pin, clock input pin and gain factor.
|
||||||
|
// Channel selection is made by passing the appropriate gain:
|
||||||
|
// - With a gain factor of 64 or 128, channel A is selected
|
||||||
|
// - With a gain factor of 32, channel B is selected
|
||||||
|
// By omitting the gain factor parameter, the library
|
||||||
|
// default "128" (Channel A) is used here.
|
||||||
|
gCatena.SafePrintf("Setup Scale 1...\n");
|
||||||
|
//LoadCell_1.begin(A3, A2);
|
||||||
|
|
||||||
|
if (!(LoadCell_1.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 1 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scale 2...\n");
|
||||||
|
//LoadCell_2.begin(A1, A0);
|
||||||
|
|
||||||
|
if (!(LoadCell_2.wait_ready_timeout(1000))) {
|
||||||
|
gCatena.SafePrintf("Scale 2 not ready.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Setup Scales is complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_flash(void)
|
||||||
|
{
|
||||||
|
if (gFlash.begin(&gSPI2, Catena::PIN_SPI2_FLASH_SS)) {
|
||||||
|
fFlash = true;
|
||||||
|
gFlash.powerDown();
|
||||||
|
gCatena.SafePrintf("FLASH found, put power down\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fFlash = false;
|
||||||
|
gFlash.end();
|
||||||
|
gSPI2.end();
|
||||||
|
gCatena.SafePrintf("No FLASH found: check hardware\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_uplink(void)
|
||||||
|
{
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
if (!(gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fManufacturingTest))) {
|
||||||
|
if (!gLoRaWAN.IsProvisioned())
|
||||||
|
gCatena.SafePrintf("LoRaWAN not provisioned yet. Use the commands to set it up.\n");
|
||||||
|
else {
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
/* warm up the BME280 by discarding a measurement */
|
||||||
|
if (fBme)
|
||||||
|
(void)gBME280.readTemperature();
|
||||||
|
|
||||||
|
/* trigger a join by sending the first packet */
|
||||||
|
ReadSensors(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Arduino loop routine -- in our case, we just drive the other loops.
|
||||||
|
// If we try to do too much, we can break the LMIC radio. So the work is
|
||||||
|
// done by outcalls scheduled from the LMIC os loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
gCatena.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearLoraData(void)
|
||||||
|
{
|
||||||
|
lora_data.version = LORA_DATA_VERSION;
|
||||||
|
lora_data.vbat = 0;
|
||||||
|
lora_data.temperature = 0;
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
lora_data.humidity[i] = 0;
|
||||||
|
lora_data.pressure[i] = 0;
|
||||||
|
lora_data.weight[i] = 0;
|
||||||
|
if (i < (MAX_VALUES_TO_SEND -1)) {
|
||||||
|
lora_data.temperature_change[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data_first.version = LORA_DATA_VERSION_FIRST_PACKAGE;
|
||||||
|
lora_data_first.vbat = 0;
|
||||||
|
lora_data_first.humidity = 0;
|
||||||
|
lora_data_first.pressure = 0;
|
||||||
|
lora_data_first.weight1 = 0;
|
||||||
|
lora_data_first.weight2 = 0;
|
||||||
|
lora_data_first.weight = 0;
|
||||||
|
lora_data_first.temperature = 0;
|
||||||
|
|
||||||
|
my_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowLORAData(bool firstTime)
|
||||||
|
{
|
||||||
|
if (firstTime) {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data_first.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data_first.vbat);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": \"%u\",\n",lora_data_first.humidity);
|
||||||
|
gCatena.SafePrintf(" \"pressure\": \"%u\",\n",lora_data_first.pressure);
|
||||||
|
gCatena.SafePrintf(" \"weight1\": \"%ld\",\n",lora_data_first.weight1);
|
||||||
|
gCatena.SafePrintf(" \"weight2\": \"%ld\",\n",lora_data_first.weight2);
|
||||||
|
gCatena.SafePrintf(" \"weight\": \"%u\",\n",lora_data_first.weight);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data_first.temperature);
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gCatena.SafePrintf("{\n");
|
||||||
|
gCatena.SafePrintf(" \"version\": \"%u\",\n",lora_data.version);
|
||||||
|
gCatena.SafePrintf(" \"vbat\": \"%u\",\n",lora_data.vbat);
|
||||||
|
gCatena.SafePrintf(" \"temperature\": \"%u\",\n",lora_data.temperature);
|
||||||
|
gCatena.SafePrintf(" \"humidity\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.humidity[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"pressure\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.pressure[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"weight\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND; i++) {
|
||||||
|
gCatena.SafePrintf("%ld",lora_data.weight[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 1)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("],\n");
|
||||||
|
gCatena.SafePrintf(" \"temperature_change\": [");
|
||||||
|
for (int i = 0; i < MAX_VALUES_TO_SEND - 1; i++) {
|
||||||
|
gCatena.SafePrintf("%d",lora_data.temperature_change[i]);
|
||||||
|
if (i < (MAX_VALUES_TO_SEND - 2)) {
|
||||||
|
gCatena.SafePrintf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("]\n");
|
||||||
|
gCatena.SafePrintf("}\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSensors(bool firstTime)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Power-Up HX711
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
LoadCell_1.power_up();
|
||||||
|
|
||||||
|
// vBat
|
||||||
|
float vBat = gCatena.ReadVbat();
|
||||||
|
gCatena.SafePrintf("vBat: %d mV\n", (int)(vBat * 1000.0f));
|
||||||
|
|
||||||
|
// vBus
|
||||||
|
float vBus = gCatena.ReadVbus();
|
||||||
|
gCatena.SafePrintf("vBus: %d mV\n", (int)(vBus * 1000.0f));
|
||||||
|
fUsbPower = (vBus > 3.0) ? true : false;
|
||||||
|
|
||||||
|
int16_t temp_current;
|
||||||
|
uint8_t humidity_current;
|
||||||
|
uint8_t pressure_current;
|
||||||
|
int32_t weight1_current;
|
||||||
|
int32_t weight2_current;
|
||||||
|
int16_t temp_last;
|
||||||
|
int16_t temp_change;
|
||||||
|
uint16_t weight_current;
|
||||||
|
uint16_t weight_last;
|
||||||
|
|
||||||
|
|
||||||
|
if (fBme) {
|
||||||
|
Adafruit_BME280::Measurements m = gBME280.readTemperaturePressureHumidity();
|
||||||
|
// temperature is 2 bytes from -0x80.00 to +0x7F.FF degrees C
|
||||||
|
// pressure is 2 bytes, hPa * 10.
|
||||||
|
// humidity is one byte, where 0 == 0/256 and 0xFF == 255/256.
|
||||||
|
gCatena.SafePrintf(
|
||||||
|
"BME280: T: %d P: %d RH: %d\n",
|
||||||
|
(int)m.Temperature,
|
||||||
|
(int)m.Pressure,
|
||||||
|
(int)m.Humidity);
|
||||||
|
temp_current = (int16_t)((m.Temperature) * 10);
|
||||||
|
humidity_current = (uint8_t)m.Humidity;
|
||||||
|
pressure_current = (uint8_t)((m.Pressure / 100) - PRESSURE_OFFSET);
|
||||||
|
gCatena.SafePrintf("pressure_current: %d\n",pressure_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gCatena.SafePrintf("Before Read Scales\n");
|
||||||
|
if (LoadCell_1.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_1 is ready.");
|
||||||
|
long w1 = LoadCell_1.read_average(5);
|
||||||
|
weight1_current = (int32_t)w1;
|
||||||
|
gCatena.SafePrintf("Load_cell 1 output val: %ld\n", w1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_1 not ready.");
|
||||||
|
}
|
||||||
|
if (LoadCell_2.is_ready()) {
|
||||||
|
Serial.println("HX711 LoadCell_2 is ready.");
|
||||||
|
long w2 = LoadCell_2.read_average(5);
|
||||||
|
weight2_current = (int32_t)w2;
|
||||||
|
gCatena.SafePrintf("Load_cell 2 output val: %ld\n", w2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("HX711 LoadCell_2 not ready.");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("After Read Scales\n");
|
||||||
|
|
||||||
|
// Power-Down HX711
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
LoadCell_1.power_down();
|
||||||
|
|
||||||
|
|
||||||
|
// Gewicht berechnen
|
||||||
|
weight_current = ((weight1_current - config_data.cal_w1_0) / config_data.cal_w1_factor) + ((weight2_current - config_data.cal_w2_0) / config_data.cal_w2_factor);
|
||||||
|
|
||||||
|
// calculate last value
|
||||||
|
weight_last = 0;
|
||||||
|
temp_last = lora_data.temperature;
|
||||||
|
|
||||||
|
for (int i = 0; i < my_position; i++) {
|
||||||
|
temp_last = temp_last + lora_data.temperature_change[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position > 0) {
|
||||||
|
weight_last = lora_data.weight[my_position - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
lora_data_first.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data_first.weight1 = weight1_current;
|
||||||
|
lora_data_first.weight2 = weight2_current;
|
||||||
|
lora_data_first.weight = weight_current;
|
||||||
|
lora_data_first.temperature = temp_current;
|
||||||
|
lora_data_first.humidity = humidity_current;
|
||||||
|
lora_data_first.pressure = pressure_current;
|
||||||
|
} else {
|
||||||
|
lora_data.vbat = (uint8_t)(vBat * 1000.0f / 20);
|
||||||
|
lora_data.weight[my_position] = weight_current;
|
||||||
|
if (my_position == 0) {
|
||||||
|
lora_data.temperature = temp_current;
|
||||||
|
} else {
|
||||||
|
temp_change = temp_current - temp_last;
|
||||||
|
if (temp_change > 127) {
|
||||||
|
temp_change = 127;
|
||||||
|
}
|
||||||
|
if (temp_change < -128) {
|
||||||
|
temp_change = -128;
|
||||||
|
}
|
||||||
|
|
||||||
|
lora_data.temperature_change[my_position - 1] = (uint8_t)temp_change;
|
||||||
|
}
|
||||||
|
lora_data.humidity[my_position] = humidity_current;
|
||||||
|
lora_data.pressure[my_position] = pressure_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_position == 0) {
|
||||||
|
timer_pos0 = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowLORAData(firstTime);
|
||||||
|
my_position++;
|
||||||
|
|
||||||
|
// Should we send the Data?
|
||||||
|
// we send data the first time the system is started, when the array is full
|
||||||
|
// or when the weight has fallen more than 100g or the first measurement is
|
||||||
|
// more than one hour old (which should not happen :-) )
|
||||||
|
if (firstTime || (my_position >= MAX_VALUES_TO_SEND) || ((weight_last - weight_current) > 20) || ((millis() - timer_pos0) > 3600000)) {
|
||||||
|
lora_data.offset_last_reading = (uint8_t)((millis() - timer_pos0) / 1000 / 60);
|
||||||
|
gCatena.SafePrintf("startSendingUplink()\n");
|
||||||
|
startSendingUplink(firstTime);
|
||||||
|
} else {
|
||||||
|
doLightSleep(&sensorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startSendingUplink(bool firstTime)
|
||||||
|
{
|
||||||
|
LedPattern savedLed = gLed.Set(LedPattern::Measuring);
|
||||||
|
|
||||||
|
if (savedLed != LedPattern::Joining)
|
||||||
|
gLed.Set(LedPattern::Sending);
|
||||||
|
else
|
||||||
|
gLed.Set(LedPattern::Joining);
|
||||||
|
|
||||||
|
bool fConfirmed = false;
|
||||||
|
if (gCatena.GetOperatingFlags() & (1 << 16)) {
|
||||||
|
gCatena.SafePrintf("requesting confirmed tx\n");
|
||||||
|
fConfirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data_first, sizeof(LORA_data_first), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
} else {
|
||||||
|
gLoRaWAN.SendBuffer((uint8_t*)&lora_data, sizeof(LORA_data), sendBufferDoneCb, NULL, fConfirmed);
|
||||||
|
}
|
||||||
|
ClearLoraData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendBufferDoneCb(
|
||||||
|
void* pContext,
|
||||||
|
bool fStatus)
|
||||||
|
{
|
||||||
|
osjobcb_t pFn;
|
||||||
|
|
||||||
|
gLed.Set(LedPattern::Settling);
|
||||||
|
if (!fStatus) {
|
||||||
|
gCatena.SafePrintf("send buffer failed\n");
|
||||||
|
pFn = txFailedDoneCb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pFn = settleDoneCb;
|
||||||
|
}
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_SETTLE),
|
||||||
|
pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txFailedDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
gCatena.SafePrintf("not provisioned, idling\n");
|
||||||
|
gLoRaWAN.Shutdown();
|
||||||
|
gLed.Set(LedPattern::NotProvisioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settleDoneCb(
|
||||||
|
osjob_t* pSendJob)
|
||||||
|
{
|
||||||
|
const bool fDeepSleep = checkDeepSleep();
|
||||||
|
|
||||||
|
if (!g_fPrintedSleeping)
|
||||||
|
doSleepAlert(fDeepSleep);
|
||||||
|
|
||||||
|
if (fDeepSleep)
|
||||||
|
doDeepSleep(pSendJob);
|
||||||
|
else
|
||||||
|
doLightSleep(pSendJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkDeepSleep(void)
|
||||||
|
{
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
bool fDeepSleep;
|
||||||
|
|
||||||
|
if (fDeepSleepTest) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
#ifdef USBCON
|
||||||
|
else if (Serial.dtr()) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (gCatena.GetOperatingFlags() & (1 << 17)) {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
else if ((gCatena.GetOperatingFlags() & static_cast<uint32_t>(gCatena.OPERATING_FLAGS::fUnattended)) != 0) {
|
||||||
|
fDeepSleep = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fDeepSleep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fDeepSleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doSleepAlert(const bool fDeepSleep)
|
||||||
|
{
|
||||||
|
g_fPrintedSleeping = true;
|
||||||
|
|
||||||
|
if (fDeepSleep) {
|
||||||
|
bool const fDeepSleepTest = gCatena.GetOperatingFlags() & (1 << 19);
|
||||||
|
const uint32_t deepSleepDelay = fDeepSleepTest ? 10 : 30;
|
||||||
|
|
||||||
|
gCatena.SafePrintf("using deep sleep in %u secs"
|
||||||
|
#ifdef USBCON
|
||||||
|
" (USB will disconnect while asleep)"
|
||||||
|
#endif
|
||||||
|
": ",
|
||||||
|
deepSleepDelay);
|
||||||
|
|
||||||
|
// sleep and print
|
||||||
|
gLed.Set(LedPattern::TwoShort);
|
||||||
|
|
||||||
|
for (auto n = deepSleepDelay; n > 0; --n) {
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
|
||||||
|
while (uint32_t(millis() - tNow) < 1000) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf(".");
|
||||||
|
}
|
||||||
|
gCatena.SafePrintf("\nStarting deep sleep.\n");
|
||||||
|
uint32_t tNow = millis();
|
||||||
|
while (uint32_t(millis() - tNow) < 100) {
|
||||||
|
gCatena.poll();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gCatena.SafePrintf("using light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDeepSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
/* ok... now it's time for a deep sleep */
|
||||||
|
gLed.Set(LedPattern::Off);
|
||||||
|
Serial.end();
|
||||||
|
Wire.end();
|
||||||
|
SPI.end();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.end();
|
||||||
|
|
||||||
|
gCatena.Sleep(CATCFG_T_INTERVAL);
|
||||||
|
|
||||||
|
/* and now... we're awake again. trigger another measurement */
|
||||||
|
Serial.begin();
|
||||||
|
Wire.begin();
|
||||||
|
SPI.begin();
|
||||||
|
if (fFlash)
|
||||||
|
gSPI2.begin();
|
||||||
|
sleepDoneCb(pJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doLightSleep(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::Sleeping);
|
||||||
|
os_setTimedCallback(
|
||||||
|
pJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_INTERVAL),
|
||||||
|
sleepDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sleepDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
gLed.Set(LedPattern::WarmingUp);
|
||||||
|
|
||||||
|
os_setTimedCallback(
|
||||||
|
&sensorJob,
|
||||||
|
os_getTime() + sec2osticks(CATCFG_T_WARMUP),
|
||||||
|
warmupDoneCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warmupDoneCb(osjob_t* pJob)
|
||||||
|
{
|
||||||
|
ReadSensors(false);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="128"
|
||||||
|
height="128"
|
||||||
|
viewBox="0 0 33.866666 33.866668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg96"
|
||||||
|
inkscape:version="0.92.4 (unknown)"
|
||||||
|
sodipodi:docname="bee-logo-128-cutout.svg">
|
||||||
|
<defs
|
||||||
|
id="defs90" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="6.4296875"
|
||||||
|
inkscape:cx="64"
|
||||||
|
inkscape:cy="63.780818"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata93">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-263.13332)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#483737;fill-opacity:1;stroke:#483737;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="M 64.605469,3.0644531 C 61.008105,3.0003949 57.29972,4.8041766 50.607422,8.6679688 L 36.943359,16.558594 23.277344,24.447266 C 10.780426,31.662384 9.6132812,32.661981 9.6132812,48.117188 v 15.779296 15.777344 c 1e-7,14.430161 0.2794604,15.942338 13.6640628,23.669922 l 13.666015,7.88867 13.664063,7.89063 c 12.49694,7.21511 13.945505,7.72762 27.330078,0 l 13.666016,-7.89063 13.664064,-7.88867 c 12.49694,-7.21508 13.66601,-8.214716 13.66601,-23.669922 V 63.896484 48.117188 c 0,-14.430237 -0.27948,-15.942338 -13.66406,-23.669922 L 91.603516,16.558594 77.9375,8.6679688 C 71.689043,5.0604097 68.202833,3.1285114 64.605469,3.0644531 Z M 63.529297,35.904297 c 11.421218,0 22.336405,2.321093 32.257812,6.517578 a 7.5378873,7.5378873 0 1 1 -5.86914,13.876953 C 81.811305,52.86989 72.913834,50.976562 63.529297,50.976562 c -9.384397,0 -18.283969,1.893328 -26.390625,5.322266 A 7.5378873,7.5378873 0 1 1 31.261719,42.421875 c 9.921402,-4.196485 20.846473,-6.517578 32.267578,-6.517578 z m 0,20.912109 c 8.53426,0 16.703271,1.734716 24.123047,4.873047 a 7.5378874,7.5378874 0 1 1 -5.875,13.876953 c -5.605111,-2.370784 -11.750487,-3.675781 -18.248047,-3.675781 -6.497443,0 -12.650715,1.304997 -18.255859,3.675781 A 7.5378874,7.5378874 0 1 1 39.404297,61.689453 c 7.419787,-3.138331 15.590827,-4.873047 24.125,-4.873047 z m 0,20.935547 c 5.643583,0 11.059704,1.145794 15.974609,3.224609 a 7.5395547,7.5395547 0 1 1 -5.876953,13.886719 c -3.100354,-1.311345 -6.490823,-2.037109 -10.097656,-2.037109 -3.606679,0 -7.006909,0.725727 -10.107422,2.037109 A 7.5378875,7.5378875 0 1 1 47.554688,80.976562 c 4.914946,-2.078777 10.331124,-3.224609 15.974609,-3.224609 z"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,263.13332)"
|
||||||
|
id="path815"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#fc0ff0;fill-opacity:0;stroke:#483737;stroke-width:2.90305877;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 10.674714,268.54246 8.8603022,264.91363"
|
||||||
|
id="path899"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#483737;stroke-width:2.90305877;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 23.375595,268.54246 1.814411,-3.62883"
|
||||||
|
id="path899-8"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
|
@ -0,0 +1,205 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="83.081947mm"
|
||||||
|
height="52.319721mm"
|
||||||
|
viewBox="0 0 83.081947 52.319721"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (unknown)"
|
||||||
|
sodipodi:docname="mini-beieli-praegung-text-as-path.svg"
|
||||||
|
inkscape:export-filename="/home/joerg/bee-logo-box.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="DotL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="DotL"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path978"
|
||||||
|
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
|
||||||
|
style="fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||||
|
transform="matrix(0.8,0,0,0.8,5.92,0.8)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="3.1106813"
|
||||||
|
inkscape:cx="3.5729304"
|
||||||
|
inkscape:cy="42.625215"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2089"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
fit-margin-top="10"
|
||||||
|
fit-margin-left="10"
|
||||||
|
fit-margin-right="10"
|
||||||
|
fit-margin-bottom="10">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid895"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1"
|
||||||
|
originx="15.558254"
|
||||||
|
originy="-258.4087" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(15.558254,13.728425)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#483737;fill-opacity:1;stroke:#483737;stroke-width:0.42512852;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 8.7393227,11.644791 -1.0589324,0.611374 -1.0589359,0.611374 c -1.0371974,0.598824 -1.1494606,0.559109 -2.1178708,0 L 3.4446478,12.256165 2.3857128,11.644791 C 1.3485151,11.045971 1.3267775,10.928889 1.3267775,9.8106715 V 8.5879237 7.3651789 c 0,-1.1976465 0.090525,-1.2750137 1.0589353,-1.8341225 L 3.4446478,4.9196842 4.5035836,4.3083089 c 1.0371978,-0.59882 1.1494596,-0.559106 2.1178708,0 l 1.0589359,0.6113753 1.0589324,0.6113722 c 1.0371922,0.5988236 1.058929,0.7159034 1.058929,1.8341225 v 1.2227448 1.2227478 c 0,1.1976435 -0.090524,1.2750145 -1.058929,1.8341195 z"
|
||||||
|
id="path815"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="scsscsscsscsscsscss"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.231964,7.4616379 c 0.6985148,-0.295449 1.4664939,-0.4588256 2.272625,-0.4588256 0.8061387,0 1.5741179,0.1633766 2.2726329,0.4588256"
|
||||||
|
id="path846-4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.8626628,8.9546319 c 0.5046637,-0.2134551 1.0595109,-0.331491 1.6419262,-0.331491 0.5824224,0 1.1372702,0.1180359 1.6419342,0.331491"
|
||||||
|
id="path846-1-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 4.494172,10.44954 c 0.3105661,-0.131357 0.6520092,-0.203993 1.010417,-0.203993 0.3584154,0 0.699858,0.07264 1.0104178,0.203993"
|
||||||
|
id="path846-8-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:#fc0ff0;fill-opacity:0;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 3.7083008,5.2207965 3.1768908,4.1579827"
|
||||||
|
id="path899"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 7.4281735,5.2207965 7.9595827,4.1579827"
|
||||||
|
id="path899-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<g
|
||||||
|
aria-label="mini-beieli.ch"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:4.44661283px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.11116531"
|
||||||
|
id="text28">
|
||||||
|
<path
|
||||||
|
d="M 14.177507,10.866552 14.6736,6.7572427 h 0.533301 q 0.165365,0 0.260449,0.082682 0.09509,0.078548 0.09095,0.2563151 l -0.02067,0.434082 q 0.297657,-0.4216797 0.644922,-0.6242513 0.347266,-0.2067057 0.731738,-0.2067057 0.409278,0 0.644922,0.2563151 0.235645,0.2521809 0.272852,0.7317382 0.305924,-0.5084961 0.682129,-0.7482747 0.376204,-0.2397786 0.822688,-0.2397786 0.28112,0 0.49196,0.1033528 0.21084,0.1033529 0.343132,0.3017904 0.136425,0.1984375 0.181901,0.4878255 0.04961,0.289388 0.0041,0.6614583 l -0.305925,2.6127599 h -1.033528 l 0.305924,-2.6127599 q 0.04961,-0.3803385 -0.03307,-0.5374349 -0.07855,-0.1612305 -0.326595,-0.1612305 -0.16123,0 -0.322461,0.082682 -0.157096,0.078548 -0.297656,0.2315104 -0.14056,0.1529623 -0.260449,0.3762044 -0.119889,0.2191081 -0.206706,0.4960938 v 0.00413 l -0.243913,2.1208003 h -1.037662 l 0.305924,-2.6127599 q 0.04961,-0.3762044 -0.02481,-0.5374349 -0.07441,-0.1612305 -0.32246,-0.1612305 -0.173633,0 -0.338998,0.086816 -0.16123,0.086816 -0.30179,0.252181 -0.14056,0.1612305 -0.260449,0.3927409 -0.11989,0.2273763 -0.206706,0.5126302 l -0.239779,2.0670568 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path873" />
|
||||||
|
<path
|
||||||
|
d="m 22.565625,6.7613768 -0.49196,4.1051752 h -1.033528 l 0.491959,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.210839,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path875" />
|
||||||
|
<path
|
||||||
|
d="m 23.05345,10.866552 0.49196,-4.1093093 h 0.533301 q 0.169498,0 0.260449,0.082682 0.09508,0.078548 0.08682,0.2563151 l -0.02067,0.4919596 q 0.322461,-0.4506185 0.711067,-0.6697266 0.388607,-0.219108 0.802019,-0.219108 0.264583,0 0.475423,0.1033528 0.214974,0.1033529 0.351399,0.3017904 0.14056,0.1984375 0.194304,0.4878255 0.05788,0.289388 0.0124,0.6614583 l -0.305924,2.6127599 h -1.050065 l 0.310058,-2.6127599 q 0.04547,-0.3803385 -0.04961,-0.5374349 -0.09095,-0.1612305 -0.338998,-0.1612305 -0.169498,0 -0.347265,0.095085 -0.177767,0.095085 -0.343132,0.2687174 -0.16123,0.1736328 -0.297656,0.4216797 -0.132292,0.2439127 -0.21084,0.5457031 l -0.214974,1.9802404 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path877" />
|
||||||
|
<path
|
||||||
|
d="m 29.114062,6.7613768 -0.491959,4.1051752 h -1.033529 l 0.49196,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.119889,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.21084,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path879" />
|
||||||
|
<path
|
||||||
|
d="m 29.833398,8.034684 h 1.934765 l -0.107487,0.8433593 h -1.930631 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path881" />
|
||||||
|
<path
|
||||||
|
d="M 32.235318,10.866552 32.95052,4.92583 h 1.029394 l -0.32246,2.6251626 q 0.297656,-0.3927408 0.657324,-0.6201171 0.363802,-0.2315104 0.773079,-0.2315104 0.268718,0 0.483692,0.095085 0.219108,0.09095 0.37207,0.2811198 0.157096,0.1901692 0.239778,0.4836914 0.08682,0.289388 0.08682,0.6862629 0,0.5250326 -0.165365,1.0128581 -0.16123,0.4836913 -0.44235,0.8557621 -0.28112,0.37207 -0.657324,0.595312 -0.37207,0.219108 -0.79375,0.219108 -0.326595,0 -0.58291,-0.124023 -0.252181,-0.124024 -0.425814,-0.334864 l -0.03307,0.111621 q -0.04548,0.144694 -0.119889,0.214974 -0.07441,0.07028 -0.248047,0.07028 z m 2.447396,-3.3486323 q -0.165365,0 -0.338997,0.1116211 -0.169499,0.1116211 -0.33073,0.3059245 -0.157096,0.1901692 -0.293522,0.4506184 -0.136425,0.2604492 -0.23151,0.5581055 L 33.3722,9.8909014 q 0.14056,0.1322916 0.318326,0.1901696 0.177767,0.05374 0.3514,0.05374 0.264584,0 0.483692,-0.1570962 0.219108,-0.1570964 0.37207,-0.4092774 0.157096,-0.256315 0.239779,-0.5746419 0.08682,-0.3183268 0.08682,-0.6449218 0,-0.4258138 -0.144694,-0.6283854 -0.14056,-0.2025716 -0.396875,-0.2025716 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path883" />
|
||||||
|
<path
|
||||||
|
d="m 40.441535,7.7494301 q 0,0.2728516 -0.124023,0.5002279 -0.119889,0.2232421 -0.429948,0.4051432 -0.310058,0.1777669 -0.847493,0.3059244 -0.533301,0.1281576 -1.35599,0.2025716 0,0.4878255 0.227376,0.72347 0.231511,0.2315108 0.7028,0.2315108 0.297656,0 0.487825,-0.06615 0.194304,-0.066146 0.33073,-0.1446942 0.136425,-0.082682 0.239778,-0.1488281 0.107487,-0.066146 0.235645,-0.066146 0.111621,0 0.190169,0.09095 l 0.272852,0.3224606 q -0.231511,0.214974 -0.450619,0.372071 -0.219108,0.152962 -0.454753,0.256315 -0.23151,0.09922 -0.491959,0.144694 -0.256315,0.04961 -0.558106,0.04961 -0.396875,0 -0.72347,-0.124023 -0.32246,-0.124024 -0.553971,-0.3514 -0.227376,-0.23151 -0.355534,-0.5498373 -0.124023,-0.3224609 -0.124023,-0.7193359 0,-0.4836914 0.165364,-0.9301757 0.169499,-0.4506185 0.475424,-0.79375 0.310058,-0.3431315 0.74414,-0.5498372 0.438216,-0.2067057 0.979785,-0.2067057 0.355534,0 0.620117,0.095085 0.268718,0.09095 0.442351,0.2439128 0.177767,0.1488281 0.264583,0.3348632 0.09095,0.1860352 0.09095,0.3720703 z m -1.46761,-0.3183268 q -0.223242,0 -0.417546,0.078548 -0.190169,0.074414 -0.343131,0.2149739 -0.152962,0.1364258 -0.264583,0.3348633 -0.111622,0.1943034 -0.177767,0.4299479 0.553971,-0.066146 0.892968,-0.1405599 0.338998,-0.078548 0.525033,-0.1653646 0.186035,-0.09095 0.248047,-0.1901692 0.06201,-0.1033529 0.06201,-0.2191081 0,-0.062012 -0.02894,-0.1198893 -0.02894,-0.062012 -0.09508,-0.1116211 -0.06201,-0.049609 -0.16123,-0.078548 -0.09922,-0.033073 -0.239779,-0.033073 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path885" />
|
||||||
|
<path
|
||||||
|
d="m 42.42591,6.7613768 -0.49196,4.1051752 h -1.033528 l 0.491959,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115755,-0.053743 0.239779,-0.053743 0.124023,0 0.239778,0.053743 0.11989,0.049609 0.21084,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path887" />
|
||||||
|
<path
|
||||||
|
d="m 46.692317,7.7494301 q 0,0.2728516 -0.124023,0.5002279 -0.119889,0.2232421 -0.429948,0.4051432 -0.310058,0.1777669 -0.847493,0.3059244 -0.533301,0.1281576 -1.35599,0.2025716 0,0.4878255 0.227377,0.72347 0.23151,0.2315108 0.702799,0.2315108 0.297656,0 0.487825,-0.06615 0.194304,-0.066146 0.33073,-0.1446942 0.136425,-0.082682 0.239778,-0.1488281 0.107487,-0.066146 0.235645,-0.066146 0.111621,0 0.190169,0.09095 l 0.272852,0.3224606 q -0.231511,0.214974 -0.450619,0.372071 -0.219108,0.152962 -0.454752,0.256315 -0.231511,0.09922 -0.49196,0.144694 -0.256315,0.04961 -0.558106,0.04961 -0.396875,0 -0.72347,-0.124023 -0.32246,-0.124024 -0.553971,-0.3514 -0.227376,-0.23151 -0.355534,-0.5498373 -0.124023,-0.3224609 -0.124023,-0.7193359 0,-0.4836914 0.165364,-0.9301757 0.169499,-0.4506185 0.475424,-0.79375 0.310058,-0.3431315 0.74414,-0.5498372 0.438216,-0.2067057 0.979785,-0.2067057 0.355534,0 0.620117,0.095085 0.268718,0.09095 0.442351,0.2439128 0.177767,0.1488281 0.264583,0.3348632 0.09095,0.1860352 0.09095,0.3720703 z m -1.46761,-0.3183268 q -0.223242,0 -0.417546,0.078548 -0.190169,0.074414 -0.343131,0.2149739 -0.152962,0.1364258 -0.264583,0.3348633 -0.111622,0.1943034 -0.177767,0.4299479 0.553971,-0.066146 0.892968,-0.1405599 0.338998,-0.078548 0.525033,-0.1653646 0.186035,-0.09095 0.248047,-0.1901692 0.06201,-0.1033529 0.06201,-0.2191081 0,-0.062012 -0.02894,-0.1198893 -0.02894,-0.062012 -0.09509,-0.1116211 -0.06201,-0.049609 -0.16123,-0.078548 -0.09922,-0.033073 -0.239779,-0.033073 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path889" />
|
||||||
|
<path
|
||||||
|
d="M 47.134667,10.866552 47.849869,4.92583 h 1.037663 l -0.719336,5.940722 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path891" />
|
||||||
|
<path
|
||||||
|
d="m 50.760287,6.7613768 -0.491959,4.1051752 h -1.033529 l 0.49196,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.210839,0.1405599 0.09095,0.09095 0.144695,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path893" />
|
||||||
|
<path
|
||||||
|
d="m 51.38867,10.300179 q 0,-0.128158 0.04548,-0.243913 0.04961,-0.1157553 0.132291,-0.1984376 0.08682,-0.082682 0.202572,-0.1322916 0.115755,-0.049609 0.248047,-0.049609 0.132291,0 0.248047,0.049609 0.115755,0.049609 0.198437,0.1322916 0.08682,0.082682 0.136426,0.1984376 0.04961,0.115755 0.04961,0.243913 0,0.132291 -0.04961,0.248047 -0.04961,0.115755 -0.136426,0.198437 -0.08268,0.08268 -0.198437,0.128158 -0.115756,0.04961 -0.248047,0.04961 -0.132292,0 -0.248047,-0.04961 -0.115755,-0.04548 -0.202572,-0.128158 -0.08268,-0.08268 -0.132291,-0.198437 -0.04548,-0.115756 -0.04548,-0.248047 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path895" />
|
||||||
|
<path
|
||||||
|
d="m 56.672069,10.138948 q -0.202571,0.223242 -0.388607,0.376205 -0.181901,0.148828 -0.376204,0.243912 -0.194303,0.09095 -0.409277,0.128158 -0.21084,0.04134 -0.471289,0.04134 -0.359668,0 -0.644922,-0.119889 -0.28112,-0.124024 -0.479558,-0.347266 -0.194303,-0.227376 -0.30179,-0.5415688 -0.103353,-0.3183268 -0.103353,-0.7110677 0,-0.3348633 0.07028,-0.649056 0.07441,-0.3183268 0.21084,-0.5953124 0.136426,-0.2769857 0.330729,-0.5084961 0.194304,-0.2356445 0.434082,-0.4010091 0.243913,-0.1653646 0.525033,-0.2563151 0.285254,-0.095085 0.599446,-0.095085 0.413412,0 0.7028,0.144694 0.289388,0.1405599 0.51263,0.434082 l -0.338997,0.3927409 q -0.03307,0.045475 -0.08268,0.074414 -0.04961,0.028939 -0.107487,0.028939 -0.07028,0 -0.128157,-0.037207 -0.05374,-0.041341 -0.124024,-0.086816 -0.07028,-0.045475 -0.177767,-0.082682 -0.103352,-0.041341 -0.272851,-0.041341 -0.219108,0 -0.417546,0.1198893 -0.198437,0.1198893 -0.351399,0.3389974 -0.152963,0.219108 -0.243913,0.5291666 -0.09095,0.3100586 -0.09095,0.6945312 0,0.4382161 0.19017,0.6738606 0.194303,0.2315108 0.516764,0.2315108 0.223242,0 0.363802,-0.06201 0.14056,-0.062012 0.239779,-0.1364258 0.09922,-0.074414 0.177767,-0.1364258 0.08268,-0.062012 0.181901,-0.062012 0.05374,0 0.09922,0.024805 0.04961,0.024805 0.08682,0.07028 l 0.268717,0.3224607 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path897" />
|
||||||
|
<path
|
||||||
|
d="M 57.035872,10.866552 57.751073,4.92583 h 1.050065 l -0.305924,2.5052733 q 0.30179,-0.3720703 0.65319,-0.5498372 0.355534,-0.181901 0.727604,-0.181901 0.264584,0 0.475423,0.1033528 0.214974,0.1033529 0.3514,0.3017904 0.14056,0.1984375 0.194303,0.4878255 0.05788,0.289388 0.0124,0.6614583 l -0.310059,2.6127599 h -1.045931 l 0.305925,-2.6127599 q 0.04961,-0.3803385 -0.04134,-0.541569 -0.09095,-0.1653646 -0.338998,-0.1653646 -0.152962,0 -0.318327,0.086816 -0.16123,0.082682 -0.314192,0.2397787 -0.152963,0.1529622 -0.285254,0.3720702 -0.132292,0.214974 -0.223242,0.4836914 l -0.256315,2.1373368 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path900" />
|
||||||
|
</g>
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot844"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"><flowRegion
|
||||||
|
id="flowRegion846"><rect
|
||||||
|
id="rect848"
|
||||||
|
width="718.11023"
|
||||||
|
height="548.03149"
|
||||||
|
x="37.795277"
|
||||||
|
y="404.40945" /></flowRegion><flowPara
|
||||||
|
id="flowPara850" /></flowRoot> </g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -0,0 +1,205 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="83.081947mm"
|
||||||
|
height="52.319721mm"
|
||||||
|
viewBox="0 0 83.081947 52.319721"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (unknown)"
|
||||||
|
sodipodi:docname="mini-beieli-praegung-text.as-path.svg"
|
||||||
|
inkscape:export-filename="/home/joerg/bee-logo-box.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="DotL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="DotL"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path978"
|
||||||
|
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
|
||||||
|
style="fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||||
|
transform="matrix(0.8,0,0,0.8,5.92,0.8)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="3.1106813"
|
||||||
|
inkscape:cx="3.5729304"
|
||||||
|
inkscape:cy="42.625215"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2089"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
fit-margin-top="10"
|
||||||
|
fit-margin-left="10"
|
||||||
|
fit-margin-right="10"
|
||||||
|
fit-margin-bottom="10">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid895"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1"
|
||||||
|
originx="15.558254"
|
||||||
|
originy="-258.4087" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(15.558254,13.728425)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#483737;fill-opacity:1;stroke:#483737;stroke-width:0.42512852;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 8.7393227,11.644791 -1.0589324,0.611374 -1.0589359,0.611374 c -1.0371974,0.598824 -1.1494606,0.559109 -2.1178708,0 L 3.4446478,12.256165 2.3857128,11.644791 C 1.3485151,11.045971 1.3267775,10.928889 1.3267775,9.8106715 V 8.5879237 7.3651789 c 0,-1.1976465 0.090525,-1.2750137 1.0589353,-1.8341225 L 3.4446478,4.9196842 4.5035836,4.3083089 c 1.0371978,-0.59882 1.1494596,-0.559106 2.1178708,0 l 1.0589359,0.6113753 1.0589324,0.6113722 c 1.0371922,0.5988236 1.058929,0.7159034 1.058929,1.8341225 v 1.2227448 1.2227478 c 0,1.1976435 -0.090524,1.2750145 -1.058929,1.8341195 z"
|
||||||
|
id="path815"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="scsscsscsscsscsscss"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.231964,7.4616379 c 0.6985148,-0.295449 1.4664939,-0.4588256 2.272625,-0.4588256 0.8061387,0 1.5741179,0.1633766 2.2726329,0.4588256"
|
||||||
|
id="path846-4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.8626628,8.9546319 c 0.5046637,-0.2134551 1.0595109,-0.331491 1.6419262,-0.331491 0.5824224,0 1.1372702,0.1180359 1.6419342,0.331491"
|
||||||
|
id="path846-1-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 4.494172,10.44954 c 0.3105661,-0.131357 0.6520092,-0.203993 1.010417,-0.203993 0.3584154,0 0.699858,0.07264 1.0104178,0.203993"
|
||||||
|
id="path846-8-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:#fc0ff0;fill-opacity:0;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 3.7083008,5.2207965 3.1768908,4.1579827"
|
||||||
|
id="path899"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 7.4281735,5.2207965 7.9595827,4.1579827"
|
||||||
|
id="path899-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<g
|
||||||
|
aria-label="mini-beieli.ch"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:4.44661283px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.11116531"
|
||||||
|
id="text28">
|
||||||
|
<path
|
||||||
|
d="M 14.177507,10.866552 14.6736,6.7572427 h 0.533301 q 0.165365,0 0.260449,0.082682 0.09509,0.078548 0.09095,0.2563151 l -0.02067,0.434082 q 0.297657,-0.4216797 0.644922,-0.6242513 0.347266,-0.2067057 0.731738,-0.2067057 0.409278,0 0.644922,0.2563151 0.235645,0.2521809 0.272852,0.7317382 0.305924,-0.5084961 0.682129,-0.7482747 0.376204,-0.2397786 0.822688,-0.2397786 0.28112,0 0.49196,0.1033528 0.21084,0.1033529 0.343132,0.3017904 0.136425,0.1984375 0.181901,0.4878255 0.04961,0.289388 0.0041,0.6614583 l -0.305925,2.6127599 h -1.033528 l 0.305924,-2.6127599 q 0.04961,-0.3803385 -0.03307,-0.5374349 -0.07855,-0.1612305 -0.326595,-0.1612305 -0.16123,0 -0.322461,0.082682 -0.157096,0.078548 -0.297656,0.2315104 -0.14056,0.1529623 -0.260449,0.3762044 -0.119889,0.2191081 -0.206706,0.4960938 v 0.00413 l -0.243913,2.1208003 h -1.037662 l 0.305924,-2.6127599 q 0.04961,-0.3762044 -0.02481,-0.5374349 -0.07441,-0.1612305 -0.32246,-0.1612305 -0.173633,0 -0.338998,0.086816 -0.16123,0.086816 -0.30179,0.252181 -0.14056,0.1612305 -0.260449,0.3927409 -0.11989,0.2273763 -0.206706,0.5126302 l -0.239779,2.0670568 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path873" />
|
||||||
|
<path
|
||||||
|
d="m 22.565625,6.7613768 -0.49196,4.1051752 h -1.033528 l 0.491959,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.210839,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path875" />
|
||||||
|
<path
|
||||||
|
d="m 23.05345,10.866552 0.49196,-4.1093093 h 0.533301 q 0.169498,0 0.260449,0.082682 0.09508,0.078548 0.08682,0.2563151 l -0.02067,0.4919596 q 0.322461,-0.4506185 0.711067,-0.6697266 0.388607,-0.219108 0.802019,-0.219108 0.264583,0 0.475423,0.1033528 0.214974,0.1033529 0.351399,0.3017904 0.14056,0.1984375 0.194304,0.4878255 0.05788,0.289388 0.0124,0.6614583 l -0.305924,2.6127599 h -1.050065 l 0.310058,-2.6127599 q 0.04547,-0.3803385 -0.04961,-0.5374349 -0.09095,-0.1612305 -0.338998,-0.1612305 -0.169498,0 -0.347265,0.095085 -0.177767,0.095085 -0.343132,0.2687174 -0.16123,0.1736328 -0.297656,0.4216797 -0.132292,0.2439127 -0.21084,0.5457031 l -0.214974,1.9802404 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path877" />
|
||||||
|
<path
|
||||||
|
d="m 29.114062,6.7613768 -0.491959,4.1051752 h -1.033529 l 0.49196,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.119889,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.21084,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path879" />
|
||||||
|
<path
|
||||||
|
d="m 29.833398,8.034684 h 1.934765 l -0.107487,0.8433593 h -1.930631 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path881" />
|
||||||
|
<path
|
||||||
|
d="M 32.235318,10.866552 32.95052,4.92583 h 1.029394 l -0.32246,2.6251626 q 0.297656,-0.3927408 0.657324,-0.6201171 0.363802,-0.2315104 0.773079,-0.2315104 0.268718,0 0.483692,0.095085 0.219108,0.09095 0.37207,0.2811198 0.157096,0.1901692 0.239778,0.4836914 0.08682,0.289388 0.08682,0.6862629 0,0.5250326 -0.165365,1.0128581 -0.16123,0.4836913 -0.44235,0.8557621 -0.28112,0.37207 -0.657324,0.595312 -0.37207,0.219108 -0.79375,0.219108 -0.326595,0 -0.58291,-0.124023 -0.252181,-0.124024 -0.425814,-0.334864 l -0.03307,0.111621 q -0.04548,0.144694 -0.119889,0.214974 -0.07441,0.07028 -0.248047,0.07028 z m 2.447396,-3.3486323 q -0.165365,0 -0.338997,0.1116211 -0.169499,0.1116211 -0.33073,0.3059245 -0.157096,0.1901692 -0.293522,0.4506184 -0.136425,0.2604492 -0.23151,0.5581055 L 33.3722,9.8909014 q 0.14056,0.1322916 0.318326,0.1901696 0.177767,0.05374 0.3514,0.05374 0.264584,0 0.483692,-0.1570962 0.219108,-0.1570964 0.37207,-0.4092774 0.157096,-0.256315 0.239779,-0.5746419 0.08682,-0.3183268 0.08682,-0.6449218 0,-0.4258138 -0.144694,-0.6283854 -0.14056,-0.2025716 -0.396875,-0.2025716 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path883" />
|
||||||
|
<path
|
||||||
|
d="m 40.441535,7.7494301 q 0,0.2728516 -0.124023,0.5002279 -0.119889,0.2232421 -0.429948,0.4051432 -0.310058,0.1777669 -0.847493,0.3059244 -0.533301,0.1281576 -1.35599,0.2025716 0,0.4878255 0.227376,0.72347 0.231511,0.2315108 0.7028,0.2315108 0.297656,0 0.487825,-0.06615 0.194304,-0.066146 0.33073,-0.1446942 0.136425,-0.082682 0.239778,-0.1488281 0.107487,-0.066146 0.235645,-0.066146 0.111621,0 0.190169,0.09095 l 0.272852,0.3224606 q -0.231511,0.214974 -0.450619,0.372071 -0.219108,0.152962 -0.454753,0.256315 -0.23151,0.09922 -0.491959,0.144694 -0.256315,0.04961 -0.558106,0.04961 -0.396875,0 -0.72347,-0.124023 -0.32246,-0.124024 -0.553971,-0.3514 -0.227376,-0.23151 -0.355534,-0.5498373 -0.124023,-0.3224609 -0.124023,-0.7193359 0,-0.4836914 0.165364,-0.9301757 0.169499,-0.4506185 0.475424,-0.79375 0.310058,-0.3431315 0.74414,-0.5498372 0.438216,-0.2067057 0.979785,-0.2067057 0.355534,0 0.620117,0.095085 0.268718,0.09095 0.442351,0.2439128 0.177767,0.1488281 0.264583,0.3348632 0.09095,0.1860352 0.09095,0.3720703 z m -1.46761,-0.3183268 q -0.223242,0 -0.417546,0.078548 -0.190169,0.074414 -0.343131,0.2149739 -0.152962,0.1364258 -0.264583,0.3348633 -0.111622,0.1943034 -0.177767,0.4299479 0.553971,-0.066146 0.892968,-0.1405599 0.338998,-0.078548 0.525033,-0.1653646 0.186035,-0.09095 0.248047,-0.1901692 0.06201,-0.1033529 0.06201,-0.2191081 0,-0.062012 -0.02894,-0.1198893 -0.02894,-0.062012 -0.09508,-0.1116211 -0.06201,-0.049609 -0.16123,-0.078548 -0.09922,-0.033073 -0.239779,-0.033073 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path885" />
|
||||||
|
<path
|
||||||
|
d="m 42.42591,6.7613768 -0.49196,4.1051752 h -1.033528 l 0.491959,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115755,-0.053743 0.239779,-0.053743 0.124023,0 0.239778,0.053743 0.11989,0.049609 0.21084,0.1405599 0.09095,0.09095 0.144694,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path887" />
|
||||||
|
<path
|
||||||
|
d="m 46.692317,7.7494301 q 0,0.2728516 -0.124023,0.5002279 -0.119889,0.2232421 -0.429948,0.4051432 -0.310058,0.1777669 -0.847493,0.3059244 -0.533301,0.1281576 -1.35599,0.2025716 0,0.4878255 0.227377,0.72347 0.23151,0.2315108 0.702799,0.2315108 0.297656,0 0.487825,-0.06615 0.194304,-0.066146 0.33073,-0.1446942 0.136425,-0.082682 0.239778,-0.1488281 0.107487,-0.066146 0.235645,-0.066146 0.111621,0 0.190169,0.09095 l 0.272852,0.3224606 q -0.231511,0.214974 -0.450619,0.372071 -0.219108,0.152962 -0.454752,0.256315 -0.231511,0.09922 -0.49196,0.144694 -0.256315,0.04961 -0.558106,0.04961 -0.396875,0 -0.72347,-0.124023 -0.32246,-0.124024 -0.553971,-0.3514 -0.227376,-0.23151 -0.355534,-0.5498373 -0.124023,-0.3224609 -0.124023,-0.7193359 0,-0.4836914 0.165364,-0.9301757 0.169499,-0.4506185 0.475424,-0.79375 0.310058,-0.3431315 0.74414,-0.5498372 0.438216,-0.2067057 0.979785,-0.2067057 0.355534,0 0.620117,0.095085 0.268718,0.09095 0.442351,0.2439128 0.177767,0.1488281 0.264583,0.3348632 0.09095,0.1860352 0.09095,0.3720703 z m -1.46761,-0.3183268 q -0.223242,0 -0.417546,0.078548 -0.190169,0.074414 -0.343131,0.2149739 -0.152962,0.1364258 -0.264583,0.3348633 -0.111622,0.1943034 -0.177767,0.4299479 0.553971,-0.066146 0.892968,-0.1405599 0.338998,-0.078548 0.525033,-0.1653646 0.186035,-0.09095 0.248047,-0.1901692 0.06201,-0.1033529 0.06201,-0.2191081 0,-0.062012 -0.02894,-0.1198893 -0.02894,-0.062012 -0.09509,-0.1116211 -0.06201,-0.049609 -0.16123,-0.078548 -0.09922,-0.033073 -0.239779,-0.033073 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path889" />
|
||||||
|
<path
|
||||||
|
d="M 47.134667,10.866552 47.849869,4.92583 h 1.037663 l -0.719336,5.940722 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path891" />
|
||||||
|
<path
|
||||||
|
d="m 50.760287,6.7613768 -0.491959,4.1051752 h -1.033529 l 0.49196,-4.1051752 z m 0.248047,-1.1782226 q 0,0.1322917 -0.05788,0.252181 -0.05374,0.1157552 -0.148828,0.2067057 -0.09095,0.086816 -0.21084,0.1405599 -0.115755,0.049609 -0.239778,0.049609 -0.11989,0 -0.235645,-0.049609 -0.111621,-0.053744 -0.198437,-0.1405599 -0.08682,-0.09095 -0.14056,-0.2067057 -0.05374,-0.1198893 -0.05374,-0.252181 0,-0.1322917 0.05374,-0.252181 0.05374,-0.1198893 0.14056,-0.2067057 0.09095,-0.09095 0.202571,-0.144694 0.115756,-0.053743 0.239779,-0.053743 0.124023,0 0.239779,0.053743 0.119889,0.049609 0.210839,0.1405599 0.09095,0.09095 0.144695,0.2108398 0.05374,0.1157552 0.05374,0.252181 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path893" />
|
||||||
|
<path
|
||||||
|
d="m 51.38867,10.300179 q 0,-0.128158 0.04548,-0.243913 0.04961,-0.1157553 0.132291,-0.1984376 0.08682,-0.082682 0.202572,-0.1322916 0.115755,-0.049609 0.248047,-0.049609 0.132291,0 0.248047,0.049609 0.115755,0.049609 0.198437,0.1322916 0.08682,0.082682 0.136426,0.1984376 0.04961,0.115755 0.04961,0.243913 0,0.132291 -0.04961,0.248047 -0.04961,0.115755 -0.136426,0.198437 -0.08268,0.08268 -0.198437,0.128158 -0.115756,0.04961 -0.248047,0.04961 -0.132292,0 -0.248047,-0.04961 -0.115755,-0.04548 -0.202572,-0.128158 -0.08268,-0.08268 -0.132291,-0.198437 -0.04548,-0.115756 -0.04548,-0.248047 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path895" />
|
||||||
|
<path
|
||||||
|
d="m 56.672069,10.138948 q -0.202571,0.223242 -0.388607,0.376205 -0.181901,0.148828 -0.376204,0.243912 -0.194303,0.09095 -0.409277,0.128158 -0.21084,0.04134 -0.471289,0.04134 -0.359668,0 -0.644922,-0.119889 -0.28112,-0.124024 -0.479558,-0.347266 -0.194303,-0.227376 -0.30179,-0.5415688 -0.103353,-0.3183268 -0.103353,-0.7110677 0,-0.3348633 0.07028,-0.649056 0.07441,-0.3183268 0.21084,-0.5953124 0.136426,-0.2769857 0.330729,-0.5084961 0.194304,-0.2356445 0.434082,-0.4010091 0.243913,-0.1653646 0.525033,-0.2563151 0.285254,-0.095085 0.599446,-0.095085 0.413412,0 0.7028,0.144694 0.289388,0.1405599 0.51263,0.434082 l -0.338997,0.3927409 q -0.03307,0.045475 -0.08268,0.074414 -0.04961,0.028939 -0.107487,0.028939 -0.07028,0 -0.128157,-0.037207 -0.05374,-0.041341 -0.124024,-0.086816 -0.07028,-0.045475 -0.177767,-0.082682 -0.103352,-0.041341 -0.272851,-0.041341 -0.219108,0 -0.417546,0.1198893 -0.198437,0.1198893 -0.351399,0.3389974 -0.152963,0.219108 -0.243913,0.5291666 -0.09095,0.3100586 -0.09095,0.6945312 0,0.4382161 0.19017,0.6738606 0.194303,0.2315108 0.516764,0.2315108 0.223242,0 0.363802,-0.06201 0.14056,-0.062012 0.239779,-0.1364258 0.09922,-0.074414 0.177767,-0.1364258 0.08268,-0.062012 0.181901,-0.062012 0.05374,0 0.09922,0.024805 0.04961,0.024805 0.08682,0.07028 l 0.268717,0.3224607 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path897" />
|
||||||
|
<path
|
||||||
|
d="M 57.035872,10.866552 57.751073,4.92583 h 1.050065 l -0.305924,2.5052733 q 0.30179,-0.3720703 0.65319,-0.5498372 0.355534,-0.181901 0.727604,-0.181901 0.264584,0 0.475423,0.1033528 0.214974,0.1033529 0.3514,0.3017904 0.14056,0.1984375 0.194303,0.4878255 0.05788,0.289388 0.0124,0.6614583 l -0.310059,2.6127599 h -1.045931 l 0.305925,-2.6127599 q 0.04961,-0.3803385 -0.04134,-0.541569 -0.09095,-0.1653646 -0.338998,-0.1653646 -0.152962,0 -0.318327,0.086816 -0.16123,0.082682 -0.314192,0.2397787 -0.152963,0.1529622 -0.285254,0.3720702 -0.132292,0.214974 -0.223242,0.4836914 l -0.256315,2.1373368 z"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531"
|
||||||
|
id="path900" />
|
||||||
|
</g>
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot844"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"><flowRegion
|
||||||
|
id="flowRegion846"><rect
|
||||||
|
id="rect848"
|
||||||
|
width="718.11023"
|
||||||
|
height="548.03149"
|
||||||
|
x="37.795277"
|
||||||
|
y="404.40945" /></flowRegion><flowPara
|
||||||
|
id="flowPara850" /></flowRoot> </g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -0,0 +1,294 @@
|
||||||
|
%!PS-Adobe-3.0 EPSF-3.0
|
||||||
|
%%Creator: cairo 1.16.0 (https://cairographics.org)
|
||||||
|
%%CreationDate: Wed Feb 20 19:23:49 2019
|
||||||
|
%%Pages: 1
|
||||||
|
%%DocumentData: Clean7Bit
|
||||||
|
%%LanguageLevel: 2
|
||||||
|
%%BoundingBox: 47 71 217 100
|
||||||
|
%%EndComments
|
||||||
|
%%BeginProlog
|
||||||
|
50 dict begin
|
||||||
|
/q { gsave } bind def
|
||||||
|
/Q { grestore } bind def
|
||||||
|
/cm { 6 array astore concat } bind def
|
||||||
|
/w { setlinewidth } bind def
|
||||||
|
/J { setlinecap } bind def
|
||||||
|
/j { setlinejoin } bind def
|
||||||
|
/M { setmiterlimit } bind def
|
||||||
|
/d { setdash } bind def
|
||||||
|
/m { moveto } bind def
|
||||||
|
/l { lineto } bind def
|
||||||
|
/c { curveto } bind def
|
||||||
|
/h { closepath } bind def
|
||||||
|
/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
|
||||||
|
0 exch rlineto 0 rlineto closepath } bind def
|
||||||
|
/S { stroke } bind def
|
||||||
|
/f { fill } bind def
|
||||||
|
/f* { eofill } bind def
|
||||||
|
/n { newpath } bind def
|
||||||
|
/W { clip } bind def
|
||||||
|
/W* { eoclip } bind def
|
||||||
|
/BT { } bind def
|
||||||
|
/ET { } bind def
|
||||||
|
/BDC { mark 3 1 roll /BDC pdfmark } bind def
|
||||||
|
/EMC { mark /EMC pdfmark } bind def
|
||||||
|
/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
|
||||||
|
/Tj { show currentpoint cairo_store_point } bind def
|
||||||
|
/TJ {
|
||||||
|
{
|
||||||
|
dup
|
||||||
|
type /stringtype eq
|
||||||
|
{ show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
|
||||||
|
} forall
|
||||||
|
currentpoint cairo_store_point
|
||||||
|
} bind def
|
||||||
|
/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
|
||||||
|
cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
|
||||||
|
/Tf { pop /cairo_font exch def /cairo_font_matrix where
|
||||||
|
{ pop cairo_selectfont } if } bind def
|
||||||
|
/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
|
||||||
|
/cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
|
||||||
|
/cairo_font where { pop cairo_selectfont } if } bind def
|
||||||
|
/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
|
||||||
|
cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
|
||||||
|
/g { setgray } bind def
|
||||||
|
/rg { setrgbcolor } bind def
|
||||||
|
/d1 { setcachedevice } bind def
|
||||||
|
/cairo_data_source {
|
||||||
|
CairoDataIndex CairoData length lt
|
||||||
|
{ CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def }
|
||||||
|
{ () } ifelse
|
||||||
|
} def
|
||||||
|
/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def
|
||||||
|
/cairo_image { image cairo_flush_ascii85_file } def
|
||||||
|
/cairo_imagemask { imagemask cairo_flush_ascii85_file } def
|
||||||
|
%%EndProlog
|
||||||
|
%%BeginSetup
|
||||||
|
%%BeginResource: font Carlito-BoldItalic
|
||||||
|
11 dict begin
|
||||||
|
/FontType 42 def
|
||||||
|
/FontName /Carlito-BoldItalic def
|
||||||
|
/PaintType 0 def
|
||||||
|
/FontMatrix [ 1 0 0 1 0 0 ] def
|
||||||
|
/FontBBox [ 0 0 0 0 ] def
|
||||||
|
/Encoding 256 array def
|
||||||
|
0 1 255 { Encoding exch /.notdef put } for
|
||||||
|
Encoding 45 /hyphen put
|
||||||
|
Encoding 46 /period put
|
||||||
|
Encoding 98 /b put
|
||||||
|
Encoding 99 /c put
|
||||||
|
Encoding 101 /e put
|
||||||
|
Encoding 104 /h put
|
||||||
|
Encoding 105 /i put
|
||||||
|
Encoding 108 /l put
|
||||||
|
Encoding 109 /m put
|
||||||
|
Encoding 110 /n put
|
||||||
|
/CharStrings 11 dict dup begin
|
||||||
|
/.notdef 0 def
|
||||||
|
/m 1 def
|
||||||
|
/i 2 def
|
||||||
|
/n 3 def
|
||||||
|
/hyphen 4 def
|
||||||
|
/b 5 def
|
||||||
|
/e 6 def
|
||||||
|
/l 7 def
|
||||||
|
/period 8 def
|
||||||
|
/c 9 def
|
||||||
|
/h 10 def
|
||||||
|
end readonly def
|
||||||
|
/sfnts [
|
||||||
|
<0001000000090080000300106376742026d7027600000828000000386670676ddbb62e8c0000
|
||||||
|
086000000a75676c79667c62e8020000009c0000078c686561647d5a70d0000012d800000036
|
||||||
|
686865610e6808980000131000000024686d747826e2028c000013340000002c6c6f63610000
|
||||||
|
319400001360000000306d61787001bf0bc90000139000000020707265709a783a38000013b0
|
||||||
|
0000008100040028000003ff057600230037003b003f0088b50001020001424bb01a50584034
|
||||||
|
000302010203016800010402010466000000020300025b000400050804055b00090906510006
|
||||||
|
060e4300080807510007070d07441b4032000302010203016800010402010466000600090006
|
||||||
|
0959000000020300025b000400050804055b00080807510007070d074459400d3f3e11111428
|
||||||
|
26232a1c220a182b133e0133321e0215140e040f012327263e0435342623220e022322271334
|
||||||
|
3e0233321e0215140e0223222e020121112137211121e5388e61466e4c281a29302b220516ae
|
||||||
|
12061527312b1d292a222d211a0f2410481525321e1c3225151525321c1e322515feb803d7fc
|
||||||
|
2941034cfcb404552d3c25445f3a354c39292322155b6d24342a23272f211f260c0f0c1efd4a
|
||||||
|
1c3225151525321c1d3125151525310460fa8a4504ec0000000100370000061903f0002c005b
|
||||||
|
400c06010400201f0c03030402424bb0245058401606010404005302010200000f4308070503
|
||||||
|
03030d03441b401a0000000f430601040401530201010117430807050303030d034459400f00
|
||||||
|
00002c002c2316231524252109162b33133332160f013e01333216173e0133321e0207032313
|
||||||
|
362623220e020715032313362623220e020703377881282e010548a85d6372094ab66c446641
|
||||||
|
170b4afa4a0c273c274d443a153bfb4a0c243c2a4f443a153a03e2272b6966637b747b743260
|
||||||
|
8c5afd8802785c4d274a6b4301fdff02785b4e2a4f6f45fe0c00000000020043000001f0059d
|
||||||
|
000300170026402300020203530003030e43040101010f430000000d0044000014120a080003
|
||||||
|
00031105102b0103231301140e0223222e0235343e0233321e0201b477fa7701361b2d391e1d
|
||||||
|
372a1a1a2b371e1e392c1a03e1fc1f03e1011d20392b19192b3920203a2b1a192c3900010032
|
||||||
|
000003ec03f0001a004bb50601020301424bb024505840130003030053010100000f43050402
|
||||||
|
02020d02441b40170000000f430003030153000101174305040202020d024459400c0000001a
|
||||||
|
001a2315252106132b33133332160f013e0133321e0207032313362623220e02070332778129
|
||||||
|
2d02054ebc644067431b0b4afe4b0b2d3c29564f41133403e2272b776d6a32608c5afd880278
|
||||||
|
5c4d2e547749fe210001005101e1023e02ad00030017401400000101004d0000000151000100
|
||||||
|
0145111002112b132107216a01d41afe2d02adcc00000002003bfff1040b059d0017002800a6
|
||||||
|
4bb0225058400b1e030205041301020502421b400b1e03020504130103050242594bb00f5058
|
||||||
|
401d0000000e430701040401530001011743000505025406030202021502441b4bb022505840
|
||||||
|
1d0000000e430701040401530001011743000505025406030202021802441b40210000000e43
|
||||||
|
0701040401530001011743060103030d43000505025400020218024459594013191800002220
|
||||||
|
182819280017001628231108122b331333033e0133321e0215140e0223222627070e01230122
|
||||||
|
0e020f011e0133323e023534263badf94e48af6341694b294f88b5664f7b2a080b242a01c728
|
||||||
|
534d42171c22562a406a4b2945059dfd855f6f2d5c8d607febb46b3c331b2322032a365d7e48
|
||||||
|
e5201b4c7b9a4f67620000020031fff103c403ef002300320063400b29050201041001000102
|
||||||
|
424bb00f5058401e000104000401006805010404035300030317430000000253000202150244
|
||||||
|
1b401e00010400040100680501040403530003031743000000025300020218024459400c2524
|
||||||
|
243225322826232706132b01140e010407141633323e0233321f010e0323222e0235343e0233
|
||||||
|
321e0225220e02073e0335342e0203c43b96fefdc76f72485d42331f1b1342386a717d49609d
|
||||||
|
6f3d5195d3835681552bfe9d365d4a361086a45a1e0e1f3002f2426d573e127671202720164e
|
||||||
|
344b31173c6f9b6075d9a6642d495a2025435f3910252b311c0f1d180f000001003f000001e7
|
||||||
|
059d0003001840150000000e43020101010d01440000000300031103102b331333033fadfbae
|
||||||
|
059dfa63000000010054fff20185012000130012400f0000000153000101150144282402112b
|
||||||
|
37343e0233321e0215140e0223222e025417293820203829181829382020382917891f382818
|
||||||
|
1828381f203828171728380000000001002efff1036103ef002e0069400a1401030100010004
|
||||||
|
02424bb00f505840240002030503020568000504030504660003030153000101174300040400
|
||||||
|
530000001500441b402400020305030205680005040305046600030301530001011743000404
|
||||||
|
005300000018004459b7232623252a2406152b250e0323222e0235343e0433321617070e0123
|
||||||
|
222e0223220e0215141633323e023332161f01032e31595e673f57895f3323425e75894c648c
|
||||||
|
365208180e111b22332935604a2c5d4e36443027180d170941b036492d133b6d995f51998671
|
||||||
|
502d45475f0b0e1316133a6a965d6a711e241e0c0b4e0001003a000003ee059d0017002c4029
|
||||||
|
0301030101420000000e430003030153000101174305040202020d0244000000170017231523
|
||||||
|
1106132b331333033e0133321e0207032313362623220e0207033aadfe4a49ab5a4067431b0b
|
||||||
|
4bfd4a0c2c3c254f4a40163e059dfda25a5732608c5afd8802785c4f294b6941fdfb00000000
|
||||||
|
000000000000000000000000000000fe00c200fe00c205300000059d03e10000febe079efdda
|
||||||
|
053ffff2059d03effff1febe079efddab0002cb02060662db0012c206420b0c050b004265ab0
|
||||||
|
04455b582123211b8a5820b050505821b040591b20b038505821b038595920b00b456164b028
|
||||||
|
505821b00b4520b030505821b030591b20b0c050582066208a8a6120b00a5058601b20b02050
|
||||||
|
5821b00a601b20b036505821b036601b605959591bb0002b595923b00050586559592db0022c
|
||||||
|
204520b00425616420b005435058b0052342b00623421b212159b001602db0032c2321232120
|
||||||
|
64b105624220b0062342b20b01022a2120b00643208a208ab0002bb13005258a515860501b61
|
||||||
|
52595823592120b0405358b0002b1b21b0405923b000505865592db0042cb007432bb2000200
|
||||||
|
4360422db0052cb00723422320b000234261b0026266b00163b00160b0042a2db0062c202045
|
||||||
|
20b0024563b804006220b0005058b040605966b001636044b001602db0072c20204520b0002b
|
||||||
|
23b10804256020458a2361206420b020505821b0001bb0305058b0201bb040595923b0005058
|
||||||
|
6559b0032523614444b001602db0082cb1050545b00161442db0092cb001602020b009434ab0
|
||||||
|
00505820b009234259b00a434ab000525820b00a2342592db00a2c20b0106266b0016320b804
|
||||||
|
00638a2361b00b4360208a6020b00b2342232db00b2c4b5458b10701445924b00d6523782db0
|
||||||
|
0c2c4b51584b5358b1070144591b215924b0136523782db00d2cb1000c435558b10c0c43b001
|
||||||
|
6142b00a2b59b00043b0022542b109022542b10a022542b001162320b003255058b101004360
|
||||||
|
b00425428a8a208a2361b0092a2123b00161208a2361b0092a211bb101004360b0022542b002
|
||||||
|
2561b0092a2159b0094347b00a434760b0026220b0005058b040605966b0016320b0024563b8
|
||||||
|
04006220b0005058b040605966b0016360b10000132344b00143b0003eb20101014360422db0
|
||||||
|
0e2cb1000545545800b00c23422060b00161b50d0d01000b0042428a60b10d052bb06d2b1b22
|
||||||
|
592db00f2cb1000e2b2db0102cb1010e2b2db0112cb1020e2b2db0122cb1030e2b2db0132cb1
|
||||||
|
040e2b2db0142cb1050e2b2db0152cb1060e2b2db0162cb1070e2b2db0172cb1080e2b2db018
|
||||||
|
2cb1090e2b2db0192cb0082bb1000545545800b00c23422060b00161b50d0d01000b0042428a
|
||||||
|
60b10d052bb06d2b1b22592db01a2cb100192b2db01b2cb101192b2db01c2cb102192b2db01d
|
||||||
|
2cb103192b2db01e2cb104192b2db01f2cb105192b2db0202cb106192b2db0212cb107192b2d
|
||||||
|
b0222cb108192b2db0232cb109192b2db0242c203cb001602db0252c2060b00d60204323b001
|
||||||
|
6043b0022561b00160b0242a212db0262cb0252bb0252a2db0272c2020472020b0024563b804
|
||||||
|
006220b0005058b040605966b001636023613823208a555820472020b0024563b804006220b0
|
||||||
|
005058b040605966b00163602361381b21592db0282cb1000545545800b00116b0272ab00115
|
||||||
|
301b22592db0292cb0082bb1000545545800b00116b0272ab00115301b22592db02a2c2035b0
|
||||||
|
01602db02b2c00b0034563b804006220b0005058b040605966b00163b0002bb0024563b80400
|
||||||
|
6220b0005058b040605966b00163b0002bb00016b40000000000443e2338b12a01152a2db02c
|
||||||
|
2c203c204720b0024563b804006220b0005058b040605966b0016360b0004361382db02d2c2e
|
||||||
|
173c2db02e2c203c204720b0024563b804006220b0005058b040605966b0016360b0004361b0
|
||||||
|
014363382db02f2cb102001625202e2047b0002342b00225498a8a47234723612058621b2159
|
||||||
|
b0012342b22e010115142a2db0302cb00016b00425b004254723472361b006452b658a2e2320
|
||||||
|
203c8a382db0312cb00016b00425b00425202e472347236120b0042342b006452b20b0605058
|
||||||
|
20b0405158b3022003201bb30226031a5942422320b00843208a234723472361234660b00443
|
||||||
|
b0026220b0005058b040605966b001636020b0002b208a8a6120b00243606423b00343616450
|
||||||
|
58b00243611bb003436059b00325b0026220b0005058b040605966b0016361232020b0042623
|
||||||
|
4661381b23b0084346b00225b0084347234723616020b00443b0026220b0005058b040605966
|
||||||
|
b00163602320b0002b23b0044360b0002bb0052561b00525b0026220b0005058b040605966b0
|
||||||
|
0163b004266120b00425606423b0032560645058211b232159232020b0042623466138592db0
|
||||||
|
322cb00016202020b00526202e4723472361233c382db0332cb0001620b00823422020204623
|
||||||
|
47b0002b2361382db0342cb00016b00325b002254723472361b00054582e203c23211bb00225
|
||||||
|
b00225472347236120b00525b004254723472361b00625b0052549b0022561b0014563232058
|
||||||
|
621b215963b804006220b0005058b040605966b0016360232e2320203c8a382321592db0352c
|
||||||
|
b0001620b00843202e47234723612060b0206066b0026220b0005058b040605966b001632320
|
||||||
|
203c8a382db0362c23202e46b00225465258203c592eb12601142b2db0372c23202e46b00225
|
||||||
|
465058203c592eb12601142b2db0382c23202e46b00225465258203c5923202e46b002254650
|
||||||
|
58203c592eb12601142b2db0392cb0302b23202e46b00225465258203c592eb12601142b2db0
|
||||||
|
3a2cb0312b8a20203cb00423428a3823202e46b00225465258203c592eb12601142bb004432e
|
||||||
|
b0262b2db03b2cb00016b00425b00426202e4723472361b006452b23203c202e2338b1260114
|
||||||
|
2b2db03c2cb108042542b00016b00425b00425202e472347236120b0042342b006452b20b060
|
||||||
|
505820b0405158b3022003201bb30226031a594242232047b00443b0026220b0005058b04060
|
||||||
|
5966b001636020b0002b208a8a6120b00243606423b0034361645058b00243611bb003436059
|
||||||
|
b00325b0026220b0005058b040605966b0016361b0022546613823203c23381b212020462347
|
||||||
|
b0002b2361382159b12601142b2db03d2cb0302b2eb12601142b2db03e2cb0312b212320203c
|
||||||
|
b00423422338b12601142bb004432eb0262b2db03f2cb000152047b0002342b2000101151413
|
||||||
|
2eb02c2a2db0402cb000152047b0002342b20001011514132eb02c2a2db0412cb100011413b0
|
||||||
|
2d2a2db0422cb02f2a2db0432cb000164523202e20468a236138b12601142b2db0442cb00823
|
||||||
|
42b0432b2db0452cb200003c2b2db0462cb200013c2b2db0472cb201003c2b2db0482cb20101
|
||||||
|
3c2b2db0492cb200003d2b2db04a2cb200013d2b2db04b2cb201003d2b2db04c2cb201013d2b
|
||||||
|
2db04d2cb20000392b2db04e2cb20001392b2db04f2cb20100392b2db0502cb20101392b2db0
|
||||||
|
512cb200003b2b2db0522cb200013b2b2db0532cb201003b2b2db0542cb201013b2b2db0552c
|
||||||
|
b200003e2b2db0562cb200013e2b2db0572cb201003e2b2db0582cb201013e2b2db0592cb200
|
||||||
|
003a2b2db05a2cb200013a2b2db05b2cb201003a2b2db05c2cb201013a2b2db05d2cb0322b2e
|
||||||
|
b12601142b2db05e2cb0322bb0362b2db05f2cb0322bb0372b2db0602cb00016b0322bb0382b
|
||||||
|
2db0612cb0332b2eb12601142b2db0622cb0332bb0362b2db0632cb0332bb0372b2db0642cb0
|
||||||
|
332bb0382b2db0652cb0342b2eb12601142b2db0662cb0342bb0362b2db0672cb0342bb0372b
|
||||||
|
2db0682cb0342bb0382b2db0692cb0352b2eb12601142b2db06a2cb0352bb0362b2db06b2cb0
|
||||||
|
352bb0372b2db06c2cb0352bb0382b2db06d2c2bb00865b003245078b00115302d0000000001
|
||||||
|
000000011a5e61392c2f5f0f3cf5001b0800000000004a53db2600000000ce2e3052fc8dfdd6
|
||||||
|
09190828000300060002000100000000000100000600fe0001c40aa0fc8df7ed0919080000fb
|
||||||
|
000000000000000000000000000b040e0028066e003701f7004304380032027300510439003b
|
||||||
|
03ee003101f7003f02230054034b002e0438003a00000000000001440000022c000002a40000
|
||||||
|
03480000037c000004a000000598000005cc000006200000070c0000078c00010000000b00f5
|
||||||
|
00100000000000020050005d006e000000e50a75000000004bb800c85258b101018e59b90800
|
||||||
|
08006320b0012344b0032370b017452020b0286066208a5558b0022561b00145632362b00223
|
||||||
|
44b20b01062ab20c06062ab21406062a59b2042809455244b20c08072ab1060144b124018851
|
||||||
|
58b0408858b1060344b12601885158b804008858b106014459595959b801ff85b0048db10500
|
||||||
|
4400000000>
|
||||||
|
] def
|
||||||
|
/f-0-0 currentdict end definefont pop
|
||||||
|
%%EndResource
|
||||||
|
%%EndSetup
|
||||||
|
%%Page: 1 1
|
||||||
|
%%BeginPageSetup
|
||||||
|
%%PageBoundingBox: 47 71 217 100
|
||||||
|
%%EndPageSetup
|
||||||
|
q 47 71 170 29 rectclip
|
||||||
|
1 0 0 -1 0 149 cm q
|
||||||
|
0.282353 0.215686 0.215686 rg
|
||||||
|
68.875 71.926 m 65.875 73.656 l 62.871 75.391 l 59.93 77.086 59.613 76.977
|
||||||
|
56.867 75.391 c 53.867 73.656 l 50.863 71.926 l 47.926 70.227 47.863 69.895
|
||||||
|
47.863 66.727 c 47.863 59.793 l 47.863 56.398 48.121 56.18 50.863 54.594
|
||||||
|
c 53.867 52.859 l 56.867 51.129 l 59.809 49.43 60.125 49.543 62.871 51.129
|
||||||
|
c 65.875 52.859 l 68.875 54.594 l 71.816 56.293 71.875 56.625 71.875 59.793
|
||||||
|
c 71.875 66.727 l 71.875 70.121 71.621 70.34 68.875 71.926 c h
|
||||||
|
68.875 71.926 m f
|
||||||
|
1.205089 w
|
||||||
|
1 J
|
||||||
|
1 j
|
||||||
|
[] 0.0 d
|
||||||
|
4 M q 1 0 0 1 0 0 cm
|
||||||
|
68.875 71.926 m 65.875 73.656 l 62.871 75.391 l 59.93 77.086 59.613 76.977
|
||||||
|
56.867 75.391 c 53.867 73.656 l 50.863 71.926 l 47.926 70.227 47.863 69.895
|
||||||
|
47.863 66.727 c 47.863 59.793 l 47.863 56.398 48.121 56.18 50.863 54.594
|
||||||
|
c 53.867 52.859 l 56.867 51.129 l 59.809 49.43 60.125 49.543 62.871 51.129
|
||||||
|
c 65.875 52.859 l 68.875 54.594 l 71.816 56.293 71.875 56.625 71.875 59.793
|
||||||
|
c 71.875 66.727 l 71.875 70.121 71.621 70.34 68.875 71.926 c h
|
||||||
|
68.875 71.926 m S Q
|
||||||
|
1 0.8 0 rg
|
||||||
|
3.31125 w
|
||||||
|
q 1 0 0 1 0 0 cm
|
||||||
|
53.262 60.066 m 55.242 59.23 57.422 58.766 59.707 58.766 c 61.992 58.766
|
||||||
|
64.168 59.23 66.148 60.066 c S Q
|
||||||
|
q 1 0 0 1 0 0 cm
|
||||||
|
55.051 64.297 m 56.48 63.695 58.055 63.359 59.707 63.359 c 61.355 63.359
|
||||||
|
62.93 63.695 64.359 64.297 c S Q
|
||||||
|
q 1 0 0 1 0 0 cm
|
||||||
|
56.84 68.535 m 57.723 68.164 58.691 67.957 59.707 67.957 c 60.723 67.957
|
||||||
|
61.691 68.164 62.57 68.535 c S Q
|
||||||
|
0.282353 0.215686 0.215686 rg
|
||||||
|
2.410177 w
|
||||||
|
0 j
|
||||||
|
q 1 0 0 1 0 0 cm
|
||||||
|
54.613 53.715 m 53.109 50.703 l S Q
|
||||||
|
q 1 0 0 1 0 0 cm
|
||||||
|
65.16 53.715 m 66.664 50.703 l S Q
|
||||||
|
BT
|
||||||
|
23.999999 0 0 -23.999999 83.645814 69.718046 Tm
|
||||||
|
/f-0-0 1 Tf
|
||||||
|
[(mini-be)-3(ieli.)-3(ch)]TJ
|
||||||
|
ET
|
||||||
|
Q Q
|
||||||
|
showpage
|
||||||
|
%%Trailer
|
||||||
|
end
|
||||||
|
%%EOF
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="83.081947mm"
|
||||||
|
height="52.319721mm"
|
||||||
|
viewBox="0 0 83.081947 52.319721"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (unknown)"
|
||||||
|
sodipodi:docname="mini-beieli-praegung.svg"
|
||||||
|
inkscape:export-filename="/home/joerg/bee-logo-box.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="DotL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="DotL"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path978"
|
||||||
|
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
|
||||||
|
style="fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||||
|
transform="matrix(0.8,0,0,0.8,5.92,0.8)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="3.1106813"
|
||||||
|
inkscape:cx="10.645336"
|
||||||
|
inkscape:cy="42.625215"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2089"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
fit-margin-top="10"
|
||||||
|
fit-margin-left="10"
|
||||||
|
fit-margin-right="10"
|
||||||
|
fit-margin-bottom="10">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid895"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1"
|
||||||
|
originx="15.558254"
|
||||||
|
originy="-258.4087" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(15.558254,13.728425)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#483737;fill-opacity:1;stroke:#483737;stroke-width:0.42512852;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 8.7393227,11.644791 -1.0589324,0.611374 -1.0589359,0.611374 c -1.0371974,0.598824 -1.1494606,0.559109 -2.1178708,0 L 3.4446478,12.256165 2.3857128,11.644791 C 1.3485151,11.045971 1.3267775,10.928889 1.3267775,9.8106715 V 8.5879237 7.3651789 c 0,-1.1976465 0.090525,-1.2750137 1.0589353,-1.8341225 L 3.4446478,4.9196842 4.5035836,4.3083089 c 1.0371978,-0.59882 1.1494596,-0.559106 2.1178708,0 l 1.0589359,0.6113753 1.0589324,0.6113722 c 1.0371922,0.5988236 1.058929,0.7159034 1.058929,1.8341225 v 1.2227448 1.2227478 c 0,1.1976435 -0.090524,1.2750145 -1.058929,1.8341195 z"
|
||||||
|
id="path815"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="scsscsscsscsscsscss"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.231964,7.4616379 c 0.6985148,-0.295449 1.4664939,-0.4588256 2.272625,-0.4588256 0.8061387,0 1.5741179,0.1633766 2.2726329,0.4588256"
|
||||||
|
id="path846-4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 3.8626628,8.9546319 c 0.5046637,-0.2134551 1.0595109,-0.331491 1.6419262,-0.331491 0.5824224,0 1.1372702,0.1180359 1.6419342,0.331491"
|
||||||
|
id="path846-1-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:#ffcc00;stroke-width:1.16813552;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 4.494172,10.44954 c 0.3105661,-0.131357 0.6520092,-0.203993 1.010417,-0.203993 0.3584154,0 0.699858,0.07264 1.0104178,0.203993"
|
||||||
|
id="path846-8-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csc"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:#fc0ff0;fill-opacity:0;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 3.7083008,5.2207965 3.1768908,4.1579827"
|
||||||
|
id="path899"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#483737;stroke-width:0.85025704;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 7.4281735,5.2207965 7.9595827,4.1579827"
|
||||||
|
id="path899-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:4.44661283px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.11116531"
|
||||||
|
x="13.95013"
|
||||||
|
y="10.866552"
|
||||||
|
id="text28"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan26"
|
||||||
|
x="13.95013"
|
||||||
|
y="10.866552"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;font-family:Carlito;-inkscape-font-specification:'Carlito Bold Italic';fill:#483737;fill-opacity:1;stroke-width:0.11116531">mini-beieli.ch</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot844"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"><flowRegion
|
||||||
|
id="flowRegion846"><rect
|
||||||
|
id="rect848"
|
||||||
|
width="718.11023"
|
||||||
|
height="548.03149"
|
||||||
|
x="37.795277"
|
||||||
|
y="404.40945" /></flowRegion><flowPara
|
||||||
|
id="flowPara850" /></flowRoot> </g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.2 KiB |
|
|
@ -0,0 +1,30 @@
|
||||||
|
$fn = 100;
|
||||||
|
|
||||||
|
// Head
|
||||||
|
head_length=57.13;
|
||||||
|
head_width=26.13;
|
||||||
|
head_thickness=2.4;
|
||||||
|
head_radius_corners=(44.65 - 35.6) /2.0;
|
||||||
|
offset_m12_holes = (10-2-1.6-0.1)-8.5;
|
||||||
|
|
||||||
|
module loch() {
|
||||||
|
cylinder(r=(0.15*25.4/2), h=10, center=true);
|
||||||
|
cylinder(r1=(0.23*25.4/2), r2=(0.15*25.4/2), h=((0.23-0.15)*25.4/2), center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
module m12() {
|
||||||
|
cylinder(d=12.2, h=10, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
color("red")
|
||||||
|
difference() {
|
||||||
|
minkowski() {
|
||||||
|
cube([head_length - (2 * head_radius_corners),head_width - (2 * head_radius_corners),head_thickness], center=true);
|
||||||
|
cylinder(r=head_radius_corners, h=0.1, center=true);
|
||||||
|
};
|
||||||
|
translate([-48.15/2,0,0-((0.23-0.15)*25.4/2)]) loch();
|
||||||
|
translate([48.15/2,0,0-((0.23-0.15)*25.4/2)]) loch();
|
||||||
|
translate([-20.95/2,offset_m12_holes,0]) m12();
|
||||||
|
translate([20.95/2,offset_m12_holes,0]) m12();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
$fn = 100;
|
||||||
|
|
||||||
|
// Head
|
||||||
|
head_length=57.13;
|
||||||
|
head_width=26.13;
|
||||||
|
head_thickness=2.4;
|
||||||
|
head_radius_corners=(44.65 - 35.6) /2.0;
|
||||||
|
|
||||||
|
module loch() {
|
||||||
|
cylinder(r=(0.15*25.4/2), h=10, center=true);
|
||||||
|
cylinder(r1=(0.23*25.4/2), r2=(0.15*25.4/2), h=((0.23-0.15)*25.4/2), center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
module switch() {
|
||||||
|
cube([9.2,13.8,5],center = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
module usb() {
|
||||||
|
cube([8,3.2,5],center = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
module antenne() {
|
||||||
|
cylinder(d=6.5, h=10, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
color("red")
|
||||||
|
difference() {
|
||||||
|
minkowski() {
|
||||||
|
cube([head_length - (2 * head_radius_corners),head_width - (2 * head_radius_corners),head_thickness], center=true);
|
||||||
|
cylinder(r=head_radius_corners, h=0.1, center=true);
|
||||||
|
};
|
||||||
|
translate([-48.15/2,0,0-((0.23-0.15)*25.4/2)]) loch();
|
||||||
|
translate([48.15/2,0,0-((0.23-0.15)*25.4/2)]) loch();
|
||||||
|
translate([-11.4-0.3-(8.3/2),-2.5]) switch();
|
||||||
|
translate([0,1,0]) usb();
|
||||||
|
translate([16,0,0]) antenne();
|
||||||
|
}
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 470 KiB |
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
Uploaded
|
||||||
|
|
||||||
|
23 Apr 22:40
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
EESchema-LIBRARY Version 2.4
|
||||||
|
#encoding utf-8
|
||||||
|
#
|
||||||
|
# Connector_Conn_01x02_Female
|
||||||
|
#
|
||||||
|
DEF Connector_Conn_01x02_Female J 0 40 Y N 1 F N
|
||||||
|
F0 "J" 0 100 50 H V C CNN
|
||||||
|
F1 "Connector_Conn_01x02_Female" 0 -200 50 H V C CNN
|
||||||
|
F2 "" 0 0 50 H I C CNN
|
||||||
|
F3 "" 0 0 50 H I C CNN
|
||||||
|
$FPLIST
|
||||||
|
Connector*:*_1x??_*
|
||||||
|
$ENDFPLIST
|
||||||
|
DRAW
|
||||||
|
A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120
|
||||||
|
A 0 0 20 901 -901 1 1 6 N 0 20 0 -20
|
||||||
|
P 2 1 1 6 -50 -100 -20 -100 N
|
||||||
|
P 2 1 1 6 -50 0 -20 0 N
|
||||||
|
X Pin_1 1 -200 0 150 R 50 50 1 1 P
|
||||||
|
X Pin_2 2 -200 -100 150 R 50 50 1 1 P
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# Connector_Conn_01x03_Male
|
||||||
|
#
|
||||||
|
DEF Connector_Conn_01x03_Male J 0 40 Y N 1 F N
|
||||||
|
F0 "J" 0 200 50 H V C CNN
|
||||||
|
F1 "Connector_Conn_01x03_Male" 0 -200 50 H V C CNN
|
||||||
|
F2 "" 0 0 50 H I C CNN
|
||||||
|
F3 "" 0 0 50 H I C CNN
|
||||||
|
$FPLIST
|
||||||
|
Connector*:*_1x??_*
|
||||||
|
$ENDFPLIST
|
||||||
|
DRAW
|
||||||
|
S 34 -95 0 -105 1 1 6 F
|
||||||
|
S 34 5 0 -5 1 1 6 F
|
||||||
|
S 34 105 0 95 1 1 6 F
|
||||||
|
P 2 1 1 6 50 -100 34 -100 N
|
||||||
|
P 2 1 1 6 50 0 34 0 N
|
||||||
|
P 2 1 1 6 50 100 34 100 N
|
||||||
|
X Pin_1 1 200 100 150 L 50 50 1 1 P
|
||||||
|
X Pin_2 2 200 0 150 L 50 50 1 1 P
|
||||||
|
X Pin_3 3 200 -100 150 L 50 50 1 1 P
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# Connector_Conn_01x05_Female
|
||||||
|
#
|
||||||
|
DEF Connector_Conn_01x05_Female J 0 40 Y N 1 F N
|
||||||
|
F0 "J" 0 300 50 H V C CNN
|
||||||
|
F1 "Connector_Conn_01x05_Female" 0 -300 50 H V C CNN
|
||||||
|
F2 "" 0 0 50 H I C CNN
|
||||||
|
F3 "" 0 0 50 H I C CNN
|
||||||
|
$FPLIST
|
||||||
|
Connector*:*_1x??_*
|
||||||
|
$ENDFPLIST
|
||||||
|
DRAW
|
||||||
|
A 0 -200 20 901 -901 1 1 6 N 0 -180 0 -220
|
||||||
|
A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120
|
||||||
|
A 0 0 20 901 -901 1 1 6 N 0 20 0 -20
|
||||||
|
A 0 100 20 901 -901 1 1 6 N 0 120 0 80
|
||||||
|
A 0 200 20 901 -901 1 1 6 N 0 220 0 180
|
||||||
|
P 2 1 1 6 -50 -200 -20 -200 N
|
||||||
|
P 2 1 1 6 -50 -100 -20 -100 N
|
||||||
|
P 2 1 1 6 -50 0 -20 0 N
|
||||||
|
P 2 1 1 6 -50 100 -20 100 N
|
||||||
|
P 2 1 1 6 -50 200 -20 200 N
|
||||||
|
X Pin_1 1 -200 200 150 R 50 50 1 1 P
|
||||||
|
X Pin_2 2 -200 100 150 R 50 50 1 1 P
|
||||||
|
X Pin_3 3 -200 0 150 R 50 50 1 1 P
|
||||||
|
X Pin_4 4 -200 -100 150 R 50 50 1 1 P
|
||||||
|
X Pin_5 5 -200 -200 150 R 50 50 1 1 P
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# Connector_Generic_Conn_01x01
|
||||||
|
#
|
||||||
|
DEF Connector_Generic_Conn_01x01 J 0 40 Y N 1 F N
|
||||||
|
F0 "J" 0 100 50 H V C CNN
|
||||||
|
F1 "Connector_Generic_Conn_01x01" 0 -100 50 H V C CNN
|
||||||
|
F2 "" 0 0 50 H I C CNN
|
||||||
|
F3 "" 0 0 50 H I C CNN
|
||||||
|
$FPLIST
|
||||||
|
Connector*:*
|
||||||
|
$ENDFPLIST
|
||||||
|
DRAW
|
||||||
|
S -50 5 0 -5 1 1 6 N
|
||||||
|
S -50 50 50 -50 1 1 10 f
|
||||||
|
X Pin_1 1 -200 0 150 R 50 50 1 1 P
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# MiscellaneousDevices_ADAFRUIT_FEATHER
|
||||||
|
#
|
||||||
|
DEF MiscellaneousDevices_ADAFRUIT_FEATHER U 0 40 Y Y 2 F N
|
||||||
|
F0 "U" 200 -550 60 V V C CNN
|
||||||
|
F1 "MiscellaneousDevices_ADAFRUIT_FEATHER" 200 250 60 V V C CNN
|
||||||
|
F2 "" 150 -200 60 H V C CNN
|
||||||
|
F3 "" 150 -200 60 H V C CNN
|
||||||
|
DRAW
|
||||||
|
S -150 650 150 -650 1 1 0 N
|
||||||
|
S -150 800 150 -800 2 1 0 N
|
||||||
|
X VBAT 17 -250 550 100 R 40 40 1 1 I
|
||||||
|
X EN 18 -250 450 100 R 40 40 1 1 I
|
||||||
|
X VBUS 19 -250 350 100 R 40 40 1 1 I
|
||||||
|
X 13 20 -250 250 100 R 40 40 1 1 I
|
||||||
|
X 12 21 -250 150 100 R 40 40 1 1 I
|
||||||
|
X 11 22 -250 50 100 R 40 40 1 1 I
|
||||||
|
X 10 23 -250 -50 100 R 40 40 1 1 I
|
||||||
|
X 9 24 -250 -150 100 R 40 40 1 1 I
|
||||||
|
X 6 25 -250 -250 100 R 40 40 1 1 I
|
||||||
|
X 5 26 -250 -350 100 R 40 40 1 1 I
|
||||||
|
X 3 27 -250 -450 100 R 40 40 1 1 I
|
||||||
|
X 2 28 -250 -550 100 R 40 40 1 1 I
|
||||||
|
X DIO1 1 -250 -750 100 R 40 40 2 1 I
|
||||||
|
X A2 10 -250 150 100 R 40 40 2 1 I
|
||||||
|
X A1 11 -250 250 100 R 40 40 2 1 I
|
||||||
|
X A0 12 -250 350 100 R 40 40 2 1 I
|
||||||
|
X GND 13 -250 450 100 R 40 40 2 1 I
|
||||||
|
X AREF 14 -250 550 100 R 40 40 2 1 I
|
||||||
|
X +3V3 15 -250 650 100 R 40 40 2 1 I
|
||||||
|
X RST 16 -250 750 100 R 40 40 2 1 I
|
||||||
|
X 1 2 -250 -650 100 R 40 40 2 1 I
|
||||||
|
X 0 3 -250 -550 100 R 40 40 2 1 I
|
||||||
|
X MISO 4 -250 -450 100 R 40 40 2 1 I
|
||||||
|
X MOSI 5 -250 -350 100 R 40 40 2 1 I
|
||||||
|
X SCK 6 -250 -250 100 R 40 40 2 1 I
|
||||||
|
X A5 7 -250 -150 100 R 40 40 2 1 I
|
||||||
|
X A4 8 -250 -50 100 R 40 40 2 1 I
|
||||||
|
X A3 9 -250 50 100 R 40 40 2 1 I
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# SEN-13879_SEN-13879
|
||||||
|
#
|
||||||
|
DEF SEN-13879_SEN-13879 U 0 40 Y Y 1 L N
|
||||||
|
F0 "U" -400 626 50 H V L BNN
|
||||||
|
F1 "SEN-13879_SEN-13879" -400 -700 50 H V L BNN
|
||||||
|
F2 "SPARKFUN_SEN-13879" 0 0 50 H I L BNN
|
||||||
|
F3 "Load Cell Amp Hx711" 0 0 50 H I L BNN
|
||||||
|
F4 "SparkFun" 0 0 50 H I L BNN
|
||||||
|
F5 "Unavailable" 0 0 50 H I L BNN
|
||||||
|
F6 "SEN-13879" 0 0 50 H I L BNN
|
||||||
|
F7 "None" 0 0 50 H I L BNN
|
||||||
|
F8 "None" 0 0 50 H I L BNN
|
||||||
|
DRAW
|
||||||
|
P 2 0 0 10 -400 -600 -400 600 N
|
||||||
|
P 2 0 0 10 -400 600 400 600 N
|
||||||
|
P 2 0 0 10 400 -600 -400 -600 N
|
||||||
|
P 2 0 0 10 400 600 400 -600 N
|
||||||
|
X RED 1 -500 300 100 R 40 40 0 0 B
|
||||||
|
X VDD 10 500 500 100 L 40 40 0 0 W
|
||||||
|
X B+ 11 -500 -300 100 R 40 40 0 0 I
|
||||||
|
X B- 12 -500 -400 100 R 40 40 0 0 I
|
||||||
|
X BLK 2 -500 200 100 R 40 40 0 0 B
|
||||||
|
X WHT 3 -500 100 100 R 40 40 0 0 I
|
||||||
|
X GRN 4 -500 0 100 R 40 40 0 0 I
|
||||||
|
X YLW 5 -500 -100 100 R 40 40 0 0 B
|
||||||
|
X GND 6 500 -500 100 L 40 40 0 0 W
|
||||||
|
X CLK 7 500 -200 100 L 40 40 0 0 I C
|
||||||
|
X DAT 8 500 -100 100 L 40 40 0 0 O
|
||||||
|
X VCC 9 500 400 100 L 40 40 0 0 W
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# T4145015051-001_T4145015051-001
|
||||||
|
#
|
||||||
|
DEF T4145015051-001_T4145015051-001 J 0 40 N Y 1 L N
|
||||||
|
F0 "J" -300 500 50 H V L BNN
|
||||||
|
F1 "T4145015051-001_T4145015051-001" -300 -500 50 H V L BNN
|
||||||
|
F2 "T4145015051-001" 0 0 50 H I L BNN
|
||||||
|
F3 "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P" 0 0 50 H I L BNN
|
||||||
|
F4 "https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493" 0 0 50 H I L BNN
|
||||||
|
F5 "TE Connectivity" 0 0 50 H I L BNN
|
||||||
|
F6 "Unavailable" 0 0 50 H I L BNN
|
||||||
|
F7 "None" 0 0 50 H I L BNN
|
||||||
|
F8 "T4145015051-001" 0 0 50 H I L BNN
|
||||||
|
F9 "T4145015051-001" 0 0 50 H I L BNN
|
||||||
|
F10 "None" 0 0 50 H I L BNN
|
||||||
|
DRAW
|
||||||
|
P 2 0 0 10 -300 -300 300 -300 N
|
||||||
|
P 2 0 0 10 -300 400 -300 -300 N
|
||||||
|
P 2 0 0 10 -300 400 -100 400 N
|
||||||
|
P 2 0 0 10 -100 300 100 300 N
|
||||||
|
P 2 0 0 10 -100 400 -100 300 N
|
||||||
|
P 2 0 0 10 100 300 100 400 N
|
||||||
|
P 2 0 0 10 100 400 300 400 N
|
||||||
|
P 2 0 0 10 300 -300 300 400 N
|
||||||
|
X 1 P$1 -200 400 200 D 40 40 0 0 B I
|
||||||
|
X 2 P$2 200 400 200 D 40 40 0 0 B I
|
||||||
|
X 3 P$3 200 -300 200 U 40 40 0 0 B I
|
||||||
|
X 4 P$4 -200 -300 200 U 40 40 0 0 B I
|
||||||
|
X 5 P$5 0 300 300 D 40 40 0 0 B I
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
# power_PWR_FLAG
|
||||||
|
#
|
||||||
|
DEF power_PWR_FLAG #FLG 0 0 N N 1 F P
|
||||||
|
F0 "#FLG" 0 75 50 H I C CNN
|
||||||
|
F1 "power_PWR_FLAG" 0 150 50 H V C CNN
|
||||||
|
F2 "" 0 0 50 H I C CNN
|
||||||
|
F3 "" 0 0 50 H I C CNN
|
||||||
|
DRAW
|
||||||
|
P 6 0 1 0 0 0 0 50 -40 75 0 100 40 75 0 50 N
|
||||||
|
X pwr 1 0 0 0 U 50 50 0 0 w
|
||||||
|
ENDDRAW
|
||||||
|
ENDDEF
|
||||||
|
#
|
||||||
|
#End Library
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
EESchema-DOCLIB Version 2.0
|
||||||
|
#
|
||||||
|
#End Doc Library
|
||||||
|
|
@ -0,0 +1,406 @@
|
||||||
|
EESchema Schematic File Version 4
|
||||||
|
LIBS:beieliscale-kicad-cache
|
||||||
|
EELAYER 29 0
|
||||||
|
EELAYER END
|
||||||
|
$Descr A4 11693 8268
|
||||||
|
encoding utf-8
|
||||||
|
Sheet 1 1
|
||||||
|
Title ""
|
||||||
|
Date ""
|
||||||
|
Rev ""
|
||||||
|
Comp ""
|
||||||
|
Comment1 ""
|
||||||
|
Comment2 ""
|
||||||
|
Comment3 ""
|
||||||
|
Comment4 ""
|
||||||
|
$EndDescr
|
||||||
|
$Comp
|
||||||
|
L SEN-13879:SEN-13879 HX711-1
|
||||||
|
U 1 1 5C8AE7C5
|
||||||
|
P 4550 3350
|
||||||
|
F 0 "HX711-1" H 4550 4117 50 0000 C CNN
|
||||||
|
F 1 "SEN-13879" H 4550 4026 50 0000 C CNN
|
||||||
|
F 2 "SPARKFUN_SEN-13879" H 4550 3350 50 0001 L BNN
|
||||||
|
F 3 "Load Cell Amp Hx711" H 4550 3350 50 0001 L BNN
|
||||||
|
F 4 "SparkFun" H 4550 3350 50 0001 L BNN "Field4"
|
||||||
|
F 5 "Unavailable" H 4550 3350 50 0001 L BNN "Field5"
|
||||||
|
F 6 "SEN-13879" H 4550 3350 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 4550 3350 50 0001 L BNN "Field7"
|
||||||
|
F 8 "None" H 4550 3350 50 0001 L BNN "Field8"
|
||||||
|
1 4550 3350
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6700 3550 6700 3150
|
||||||
|
Wire Wire Line
|
||||||
|
6700 3150 6850 3150
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3550 6700 3550
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3450 6750 3450
|
||||||
|
Wire Wire Line
|
||||||
|
6750 3450 6750 3250
|
||||||
|
Wire Wire Line
|
||||||
|
6750 3250 6850 3250
|
||||||
|
NoConn ~ 6850 2950
|
||||||
|
NoConn ~ 4050 3650
|
||||||
|
NoConn ~ 4050 3750
|
||||||
|
Wire Wire Line
|
||||||
|
5050 2950 5600 2950
|
||||||
|
Wire Wire Line
|
||||||
|
5600 2950 5600 2850
|
||||||
|
$Comp
|
||||||
|
L power:PWR_FLAG #FLG0101
|
||||||
|
U 1 1 5C8B848F
|
||||||
|
P 6000 2850
|
||||||
|
F 0 "#FLG0101" H 6000 2925 50 0001 C CNN
|
||||||
|
F 1 "PWR_FLAG" H 6000 3024 50 0000 C CNN
|
||||||
|
F 2 "" H 6000 2850 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 2850 50 0001 C CNN
|
||||||
|
1 6000 2850
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
5050 2850 5600 2850
|
||||||
|
Connection ~ 5600 2850
|
||||||
|
Wire Wire Line
|
||||||
|
5600 2850 5700 2850
|
||||||
|
Wire Wire Line
|
||||||
|
5500 3850 5500 3050
|
||||||
|
NoConn ~ 8700 3050
|
||||||
|
NoConn ~ 8700 3250
|
||||||
|
NoConn ~ 8700 3650
|
||||||
|
NoConn ~ 8700 3750
|
||||||
|
NoConn ~ 8700 3850
|
||||||
|
$Comp
|
||||||
|
L power:PWR_FLAG #FLG0102
|
||||||
|
U 1 1 5C8C2453
|
||||||
|
P 5250 3850
|
||||||
|
F 0 "#FLG0102" H 5250 3925 50 0001 C CNN
|
||||||
|
F 1 "PWR_FLAG" H 5250 4024 50 0000 C CNN
|
||||||
|
F 2 "" H 5250 3850 50 0001 C CNN
|
||||||
|
F 3 "~" H 5250 3850 50 0001 C CNN
|
||||||
|
1 5250 3850
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Connection ~ 5250 3850
|
||||||
|
$Comp
|
||||||
|
L SEN-13879:SEN-13879 HX711-2
|
||||||
|
U 1 1 5C8CD302
|
||||||
|
P 4550 5100
|
||||||
|
F 0 "HX711-2" H 4550 5867 50 0000 C CNN
|
||||||
|
F 1 "SEN-13879" H 4550 5776 50 0000 C CNN
|
||||||
|
F 2 "SPARKFUN_SEN-13879" H 4550 5100 50 0001 L BNN
|
||||||
|
F 3 "Load Cell Amp Hx711" H 4550 5100 50 0001 L BNN
|
||||||
|
F 4 "SparkFun" H 4550 5100 50 0001 L BNN "Field4"
|
||||||
|
F 5 "Unavailable" H 4550 5100 50 0001 L BNN "Field5"
|
||||||
|
F 6 "SEN-13879" H 4550 5100 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 4550 5100 50 0001 L BNN "Field7"
|
||||||
|
F 8 "None" H 4550 5100 50 0001 L BNN "Field8"
|
||||||
|
1 4550 5100
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 4050 5400
|
||||||
|
NoConn ~ 4050 5500
|
||||||
|
Wire Wire Line
|
||||||
|
5050 4600 5600 4600
|
||||||
|
Wire Wire Line
|
||||||
|
5600 4600 5600 2950
|
||||||
|
Connection ~ 5600 2950
|
||||||
|
Wire Wire Line
|
||||||
|
5050 4700 5600 4700
|
||||||
|
Wire Wire Line
|
||||||
|
5600 4700 5600 4600
|
||||||
|
Connection ~ 5600 4600
|
||||||
|
Wire Wire Line
|
||||||
|
5050 5600 5250 5600
|
||||||
|
Wire Wire Line
|
||||||
|
5250 5600 5250 3850
|
||||||
|
Wire Wire Line
|
||||||
|
6650 5300 6650 3350
|
||||||
|
Wire Wire Line
|
||||||
|
6650 3350 6850 3350
|
||||||
|
Wire Wire Line
|
||||||
|
5050 5300 6650 5300
|
||||||
|
$Comp
|
||||||
|
L MiscellaneousDevices:ADAFRUIT_FEATHER U1
|
||||||
|
U 1 1 5C8BFC62
|
||||||
|
P 8950 3300
|
||||||
|
F 0 "U1" H 9128 3353 60 0000 L CNN
|
||||||
|
F 1 "MCCI 4610" H 9128 3247 60 0000 L CNN
|
||||||
|
F 2 "" H 9100 3100 60 0000 C CNN
|
||||||
|
F 3 "" H 9100 3100 60 0000 C CNN
|
||||||
|
1 8950 3300
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 8700 2850
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x02_Female BAT1
|
||||||
|
U 1 1 5C92F7C2
|
||||||
|
P 4350 1900
|
||||||
|
F 0 "BAT1" H 4244 1575 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x02_Female" H 4244 1666 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical" H 4350 1900 50 0001 C CNN
|
||||||
|
F 3 "~" H 4350 1900 50 0001 C CNN
|
||||||
|
1 4350 1900
|
||||||
|
-1 0 0 1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
8150 1900 8150 2750
|
||||||
|
Wire Wire Line
|
||||||
|
8150 2750 8700 2750
|
||||||
|
Wire Wire Line
|
||||||
|
5250 3850 5500 3850
|
||||||
|
$Comp
|
||||||
|
L T4145015051-001:T4145015051-001 J2
|
||||||
|
U 1 1 5CA65D1D
|
||||||
|
P 2950 5000
|
||||||
|
F 0 "J2" V 2483 5050 50 0000 C CNN
|
||||||
|
F 1 "T4145015051-001" V 2574 5050 50 0000 C CNN
|
||||||
|
F 2 "T4145015051-001" H 2950 5000 50 0001 L BNN
|
||||||
|
F 3 "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P" H 2950 5000 50 0001 L BNN
|
||||||
|
F 4 "https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493" H 2950 5000 50 0001 L BNN "Field4"
|
||||||
|
F 5 "TE Connectivity" H 2950 5000 50 0001 L BNN "Field5"
|
||||||
|
F 6 "Unavailable" H 2950 5000 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 2950 5000 50 0001 L BNN "Field7"
|
||||||
|
F 8 "T4145015051-001" H 2950 5000 50 0001 L BNN "Field8"
|
||||||
|
F 9 "T4145015051-001" H 2950 5000 50 0001 L BNN "Field9"
|
||||||
|
F 10 "None" H 2950 5000 50 0001 L BNN "Field10"
|
||||||
|
1 2950 5000
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
$Comp
|
||||||
|
L T4145015051-001:T4145015051-001 J1
|
||||||
|
U 1 1 5CA66C31
|
||||||
|
P 2950 3250
|
||||||
|
F 0 "J1" V 2483 3300 50 0000 C CNN
|
||||||
|
F 1 "T4145015051-001" V 2574 3300 50 0000 C CNN
|
||||||
|
F 2 "T4145015051-001" H 2950 3250 50 0001 L BNN
|
||||||
|
F 3 "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P" H 2950 3250 50 0001 L BNN
|
||||||
|
F 4 "https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493" H 2950 3250 50 0001 L BNN "Field4"
|
||||||
|
F 5 "TE Connectivity" H 2950 3250 50 0001 L BNN "Field5"
|
||||||
|
F 6 "Unavailable" H 2950 3250 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 2950 3250 50 0001 L BNN "Field7"
|
||||||
|
F 8 "T4145015051-001" H 2950 3250 50 0001 L BNN "Field8"
|
||||||
|
F 9 "T4145015051-001" H 2950 3250 50 0001 L BNN "Field9"
|
||||||
|
F 10 "None" H 2950 3250 50 0001 L BNN "Field10"
|
||||||
|
1 2950 3250
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3050 3350 3050
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3150 3450 3150
|
||||||
|
Wire Wire Line
|
||||||
|
3450 3150 3450 3450
|
||||||
|
Wire Wire Line
|
||||||
|
3450 3450 3350 3450
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3250 3650 3250
|
||||||
|
Wire Wire Line
|
||||||
|
3650 3250 3650 3650
|
||||||
|
Wire Wire Line
|
||||||
|
3650 3650 2650 3650
|
||||||
|
Wire Wire Line
|
||||||
|
2650 3650 2650 3450
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3350 3750 3350
|
||||||
|
Wire Wire Line
|
||||||
|
3750 3350 3750 3800
|
||||||
|
Wire Wire Line
|
||||||
|
3750 3800 2450 3800
|
||||||
|
Wire Wire Line
|
||||||
|
2450 3800 2450 3050
|
||||||
|
Wire Wire Line
|
||||||
|
2450 3050 2650 3050
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3450 3850 3450
|
||||||
|
Wire Wire Line
|
||||||
|
3850 3450 3850 3900
|
||||||
|
Wire Wire Line
|
||||||
|
3850 3900 3250 3900
|
||||||
|
Wire Wire Line
|
||||||
|
3250 3900 3250 3250
|
||||||
|
Wire Wire Line
|
||||||
|
4050 4800 3350 4800
|
||||||
|
Wire Wire Line
|
||||||
|
4050 4900 3500 4900
|
||||||
|
Wire Wire Line
|
||||||
|
3500 4900 3500 5200
|
||||||
|
Wire Wire Line
|
||||||
|
3500 5200 3350 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4050 5000 3600 5000
|
||||||
|
Wire Wire Line
|
||||||
|
3600 5000 3600 5400
|
||||||
|
Wire Wire Line
|
||||||
|
3600 5400 2500 5400
|
||||||
|
Wire Wire Line
|
||||||
|
2500 5400 2500 5200
|
||||||
|
Wire Wire Line
|
||||||
|
2500 5200 2650 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4050 5100 3700 5100
|
||||||
|
Wire Wire Line
|
||||||
|
3700 5100 3700 5550
|
||||||
|
Wire Wire Line
|
||||||
|
3700 5550 2400 5550
|
||||||
|
Wire Wire Line
|
||||||
|
2400 5550 2400 4800
|
||||||
|
Wire Wire Line
|
||||||
|
2400 4800 2650 4800
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5200 3750 5600
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5600 3250 5600
|
||||||
|
Wire Wire Line
|
||||||
|
3250 5600 3250 5000
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5200 4050 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4550 1800 5150 1800
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3850 5150 3850
|
||||||
|
Wire Wire Line
|
||||||
|
5150 3850 5250 3850
|
||||||
|
Connection ~ 5150 3850
|
||||||
|
Wire Wire Line
|
||||||
|
5150 1800 5150 3850
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x02_Female SWITCH1
|
||||||
|
U 1 1 5CAD5AEF
|
||||||
|
P 6300 1700
|
||||||
|
F 0 "SWITCH1" H 6194 1375 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x02_Female" H 6194 1466 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical" H 6300 1700 50 0001 C CNN
|
||||||
|
F 3 "~" H 6300 1700 50 0001 C CNN
|
||||||
|
1 6300 1700
|
||||||
|
0 -1 -1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6400 1900 8150 1900
|
||||||
|
Wire Wire Line
|
||||||
|
4550 1900 6300 1900
|
||||||
|
NoConn ~ 8700 2950
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x05_Female J3
|
||||||
|
U 1 1 5CBF85B5
|
||||||
|
P 6000 3850
|
||||||
|
F 0 "J3" H 6150 4050 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x05_Female" H 5950 4150 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B5B-PH-K_1x05_P2.00mm_Vertical" H 6000 3850 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 3850 50 0001 C CNN
|
||||||
|
1 6000 3850
|
||||||
|
-1 0 0 1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6600 4050 6600 2850
|
||||||
|
Wire Wire Line
|
||||||
|
6600 2850 6850 2850
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4050 6600 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3950 6500 3950
|
||||||
|
Wire Wire Line
|
||||||
|
6500 3950 6500 3050
|
||||||
|
Wire Wire Line
|
||||||
|
5500 3050 6500 3050
|
||||||
|
Connection ~ 6500 3050
|
||||||
|
Wire Wire Line
|
||||||
|
6500 3050 6850 3050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3650 6400 3650
|
||||||
|
Wire Wire Line
|
||||||
|
6400 3650 6400 2750
|
||||||
|
Wire Wire Line
|
||||||
|
6400 2750 6850 2750
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3850 6400 3850
|
||||||
|
Wire Wire Line
|
||||||
|
6400 3850 6400 4450
|
||||||
|
Wire Wire Line
|
||||||
|
8500 4450 8500 3550
|
||||||
|
Wire Wire Line
|
||||||
|
8500 3550 8700 3550
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3750 6550 3750
|
||||||
|
Wire Wire Line
|
||||||
|
6550 3750 6550 4350
|
||||||
|
Wire Wire Line
|
||||||
|
8400 4350 8400 3450
|
||||||
|
Wire Wire Line
|
||||||
|
8400 3450 8700 3450
|
||||||
|
Wire Wire Line
|
||||||
|
6550 4350 8400 4350
|
||||||
|
Wire Wire Line
|
||||||
|
6400 4450 8500 4450
|
||||||
|
NoConn ~ 6850 3550
|
||||||
|
$Comp
|
||||||
|
L MiscellaneousDevices:ADAFRUIT_FEATHER U1
|
||||||
|
U 2 1 5C8C025E
|
||||||
|
P 7100 3500
|
||||||
|
F 0 "U1" H 7278 3606 60 0000 L CNN
|
||||||
|
F 1 "MCCI 4610" H 7278 3500 60 0000 L CNN
|
||||||
|
F 2 "Modules:ADAFRUIT_FEATHER" H 7278 3394 60 0000 L CNN
|
||||||
|
F 3 "" H 7250 3300 60 0000 C CNN
|
||||||
|
2 7100 3500
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 6850 4250
|
||||||
|
NoConn ~ 6850 3950
|
||||||
|
NoConn ~ 6850 3850
|
||||||
|
NoConn ~ 6850 3750
|
||||||
|
NoConn ~ 6850 3650
|
||||||
|
NoConn ~ 6850 3450
|
||||||
|
Wire Wire Line
|
||||||
|
8600 5200 5050 5200
|
||||||
|
Wire Wire Line
|
||||||
|
8600 3150 8600 5200
|
||||||
|
Wire Wire Line
|
||||||
|
8600 3150 8700 3150
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x03_Male J4
|
||||||
|
U 1 1 5CFBD036
|
||||||
|
P 6000 4900
|
||||||
|
F 0 "J4" H 6108 5181 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x03_Male" H 6108 5090 50 0000 C CNN
|
||||||
|
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" H 6000 4900 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 4900 50 0001 C CNN
|
||||||
|
1 6000 4900
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6200 5600 6200 5000
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4800 6750 4800
|
||||||
|
Wire Wire Line
|
||||||
|
6750 4800 6750 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6750 4050 6850 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4900 6800 4900
|
||||||
|
Wire Wire Line
|
||||||
|
6800 4900 6800 4150
|
||||||
|
Wire Wire Line
|
||||||
|
6800 4150 6850 4150
|
||||||
|
NoConn ~ 8700 3350
|
||||||
|
Wire Wire Line
|
||||||
|
5250 5600 6200 5600
|
||||||
|
Connection ~ 5250 5600
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x01_Male J5
|
||||||
|
U 1 1 5CFE89F8
|
||||||
|
P 5500 2350
|
||||||
|
F 0 "J5" H 5608 2531 50 0000 C CNN
|
||||||
|
F 1 "VOUT1" H 5608 2440 50 0000 C CNN
|
||||||
|
F 2 "" H 5500 2350 50 0001 C CNN
|
||||||
|
F 3 "~" H 5500 2350 50 0001 C CNN
|
||||||
|
1 5500 2350
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
5700 2350 5700 2850
|
||||||
|
Connection ~ 5700 2850
|
||||||
|
Wire Wire Line
|
||||||
|
5700 2850 6000 2850
|
||||||
|
$EndSCHEMATC
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
"Id";"Designator";"Package";"Quantity";"Designation";"Supplier and ref";
|
||||||
|
1;"U2";"ADAFRUIT_FEATHER";1;"ADAFRUIT_FEATHER";;;
|
||||||
|
2;"HX711-2,HX711-1";"SPARKFUN_SEN-13879";2;"SEN-13879";;;
|
||||||
|
3;"J1,J2";"CUI_MD2-60ST";2;"Conn_01x05_Male";;;
|
||||||
|
4;"J3";"AMPHENOL_MUSB-K152-30";1;"MUSB-K152-30";;;
|
||||||
|
5;"J4";"JST_XH_B02B-XH-AM_1x02_P2.50mm_Vertical";1;"Conn_01x02_Female";;;
|
||||||
|
6;"SW1";"SW_E-Switch_EG1224_SPDT_Angled";1;"SWITCH_SPST";;;
|
||||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
|
@ -0,0 +1,369 @@
|
||||||
|
(export (version D)
|
||||||
|
(design
|
||||||
|
(source /home/joerg/git-repos/beieliscale/PCB/beieliscale-kicad/beieliscale-kicad.sch)
|
||||||
|
(date "Fr 07 Jun 2019 16:19:25 CEST")
|
||||||
|
(tool "Eeschema 5.1.2-1.fc30")
|
||||||
|
(sheet (number 1) (name /) (tstamps /)
|
||||||
|
(title_block
|
||||||
|
(title)
|
||||||
|
(company)
|
||||||
|
(rev)
|
||||||
|
(date)
|
||||||
|
(source beieliscale-kicad.sch)
|
||||||
|
(comment (number 1) (value ""))
|
||||||
|
(comment (number 2) (value ""))
|
||||||
|
(comment (number 3) (value ""))
|
||||||
|
(comment (number 4) (value "")))))
|
||||||
|
(components
|
||||||
|
(comp (ref HX711-1)
|
||||||
|
(value SEN-13879)
|
||||||
|
(footprint SPARKFUN_SEN-13879)
|
||||||
|
(datasheet "Load Cell Amp Hx711")
|
||||||
|
(fields
|
||||||
|
(field (name Field4) SparkFun)
|
||||||
|
(field (name Field5) Unavailable)
|
||||||
|
(field (name Field6) SEN-13879)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) None))
|
||||||
|
(libsource (lib SEN-13879) (part SEN-13879) (description ""))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5C8AE7C5))
|
||||||
|
(comp (ref HX711-2)
|
||||||
|
(value SEN-13879)
|
||||||
|
(footprint SPARKFUN_SEN-13879)
|
||||||
|
(datasheet "Load Cell Amp Hx711")
|
||||||
|
(fields
|
||||||
|
(field (name Field4) SparkFun)
|
||||||
|
(field (name Field5) Unavailable)
|
||||||
|
(field (name Field6) SEN-13879)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) None))
|
||||||
|
(libsource (lib SEN-13879) (part SEN-13879) (description ""))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5C8CD302))
|
||||||
|
(comp (ref U1)
|
||||||
|
(value "MCCI 4610")
|
||||||
|
(footprint Modules:ADAFRUIT_FEATHER)
|
||||||
|
(libsource (lib MiscellaneousDevices) (part ADAFRUIT_FEATHER) (description ""))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5C8BFC62))
|
||||||
|
(comp (ref BAT1)
|
||||||
|
(value Conn_01x02_Female)
|
||||||
|
(footprint Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical)
|
||||||
|
(datasheet ~)
|
||||||
|
(libsource (lib Connector) (part Conn_01x02_Female) (description "Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)"))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5C92F7C2))
|
||||||
|
(comp (ref J2)
|
||||||
|
(value T4145015051-001)
|
||||||
|
(footprint T4145015051-001)
|
||||||
|
(datasheet "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P")
|
||||||
|
(fields
|
||||||
|
(field (name Field10) None)
|
||||||
|
(field (name Field4) https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493)
|
||||||
|
(field (name Field5) "TE Connectivity")
|
||||||
|
(field (name Field6) Unavailable)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) T4145015051-001)
|
||||||
|
(field (name Field9) T4145015051-001))
|
||||||
|
(libsource (lib T4145015051-001) (part T4145015051-001) (description ""))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CA65D1D))
|
||||||
|
(comp (ref J1)
|
||||||
|
(value T4145015051-001)
|
||||||
|
(footprint T4145015051-001)
|
||||||
|
(datasheet "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P")
|
||||||
|
(fields
|
||||||
|
(field (name Field10) None)
|
||||||
|
(field (name Field4) https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493)
|
||||||
|
(field (name Field5) "TE Connectivity")
|
||||||
|
(field (name Field6) Unavailable)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) T4145015051-001)
|
||||||
|
(field (name Field9) T4145015051-001))
|
||||||
|
(libsource (lib T4145015051-001) (part T4145015051-001) (description ""))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CA66C31))
|
||||||
|
(comp (ref SWITCH1)
|
||||||
|
(value Conn_01x02_Female)
|
||||||
|
(footprint Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical)
|
||||||
|
(datasheet ~)
|
||||||
|
(libsource (lib Connector) (part Conn_01x02_Female) (description "Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)"))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CAD5AEF))
|
||||||
|
(comp (ref J3)
|
||||||
|
(value Conn_01x05_Female)
|
||||||
|
(footprint Connector_JST:JST_PH_B5B-PH-K_1x05_P2.00mm_Vertical)
|
||||||
|
(datasheet ~)
|
||||||
|
(libsource (lib Connector) (part Conn_01x05_Female) (description "Generic connector, single row, 01x05, script generated (kicad-library-utils/schlib/autogen/connector/)"))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CBF85B5))
|
||||||
|
(comp (ref J4)
|
||||||
|
(value Conn_01x03_Male)
|
||||||
|
(footprint Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical)
|
||||||
|
(datasheet ~)
|
||||||
|
(libsource (lib Connector) (part Conn_01x03_Male) (description "Generic connector, single row, 01x03, script generated (kicad-library-utils/schlib/autogen/connector/)"))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CFBD036))
|
||||||
|
(comp (ref VOUT1)
|
||||||
|
(value Conn_01x01)
|
||||||
|
(footprint Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Vertical)
|
||||||
|
(datasheet ~)
|
||||||
|
(libsource (lib Connector_Generic) (part Conn_01x01) (description "Generic connector, single row, 01x01, script generated (kicad-library-utils/schlib/autogen/connector/)"))
|
||||||
|
(sheetpath (names /) (tstamps /))
|
||||||
|
(tstamp 5CFF362B)))
|
||||||
|
(libparts
|
||||||
|
(libpart (lib Connector) (part Conn_01x02_Female)
|
||||||
|
(description "Generic connector, single row, 01x02, script generated (kicad-library-utils/schlib/autogen/connector/)")
|
||||||
|
(docs ~)
|
||||||
|
(footprints
|
||||||
|
(fp Connector*:*_1x??_*))
|
||||||
|
(fields
|
||||||
|
(field (name Reference) J)
|
||||||
|
(field (name Value) Conn_01x02_Female))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name Pin_1) (type passive))
|
||||||
|
(pin (num 2) (name Pin_2) (type passive))))
|
||||||
|
(libpart (lib Connector) (part Conn_01x03_Male)
|
||||||
|
(description "Generic connector, single row, 01x03, script generated (kicad-library-utils/schlib/autogen/connector/)")
|
||||||
|
(docs ~)
|
||||||
|
(footprints
|
||||||
|
(fp Connector*:*_1x??_*))
|
||||||
|
(fields
|
||||||
|
(field (name Reference) J)
|
||||||
|
(field (name Value) Conn_01x03_Male))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name Pin_1) (type passive))
|
||||||
|
(pin (num 2) (name Pin_2) (type passive))
|
||||||
|
(pin (num 3) (name Pin_3) (type passive))))
|
||||||
|
(libpart (lib Connector) (part Conn_01x05_Female)
|
||||||
|
(description "Generic connector, single row, 01x05, script generated (kicad-library-utils/schlib/autogen/connector/)")
|
||||||
|
(docs ~)
|
||||||
|
(footprints
|
||||||
|
(fp Connector*:*_1x??_*))
|
||||||
|
(fields
|
||||||
|
(field (name Reference) J)
|
||||||
|
(field (name Value) Conn_01x05_Female))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name Pin_1) (type passive))
|
||||||
|
(pin (num 2) (name Pin_2) (type passive))
|
||||||
|
(pin (num 3) (name Pin_3) (type passive))
|
||||||
|
(pin (num 4) (name Pin_4) (type passive))
|
||||||
|
(pin (num 5) (name Pin_5) (type passive))))
|
||||||
|
(libpart (lib Connector_Generic) (part Conn_01x01)
|
||||||
|
(description "Generic connector, single row, 01x01, script generated (kicad-library-utils/schlib/autogen/connector/)")
|
||||||
|
(docs ~)
|
||||||
|
(footprints
|
||||||
|
(fp Connector*:*))
|
||||||
|
(fields
|
||||||
|
(field (name Reference) J)
|
||||||
|
(field (name Value) Conn_01x01))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name Pin_1) (type passive))))
|
||||||
|
(libpart (lib MiscellaneousDevices) (part ADAFRUIT_FEATHER)
|
||||||
|
(fields
|
||||||
|
(field (name Reference) U)
|
||||||
|
(field (name Value) ADAFRUIT_FEATHER))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name DIO1) (type input))
|
||||||
|
(pin (num 2) (name 1) (type input))
|
||||||
|
(pin (num 3) (name 0) (type input))
|
||||||
|
(pin (num 4) (name MISO) (type input))
|
||||||
|
(pin (num 5) (name MOSI) (type input))
|
||||||
|
(pin (num 6) (name SCK) (type input))
|
||||||
|
(pin (num 7) (name A5) (type input))
|
||||||
|
(pin (num 8) (name A4) (type input))
|
||||||
|
(pin (num 9) (name A3) (type input))
|
||||||
|
(pin (num 10) (name A2) (type input))
|
||||||
|
(pin (num 11) (name A1) (type input))
|
||||||
|
(pin (num 12) (name A0) (type input))
|
||||||
|
(pin (num 13) (name GND) (type input))
|
||||||
|
(pin (num 14) (name AREF) (type input))
|
||||||
|
(pin (num 15) (name +3V3) (type input))
|
||||||
|
(pin (num 16) (name RST) (type input))
|
||||||
|
(pin (num 17) (name VBAT) (type input))
|
||||||
|
(pin (num 18) (name EN) (type input))
|
||||||
|
(pin (num 19) (name VBUS) (type input))
|
||||||
|
(pin (num 20) (name 13) (type input))
|
||||||
|
(pin (num 21) (name 12) (type input))
|
||||||
|
(pin (num 22) (name 11) (type input))
|
||||||
|
(pin (num 23) (name 10) (type input))
|
||||||
|
(pin (num 24) (name 9) (type input))
|
||||||
|
(pin (num 25) (name 6) (type input))
|
||||||
|
(pin (num 26) (name 5) (type input))
|
||||||
|
(pin (num 27) (name 3) (type input))
|
||||||
|
(pin (num 28) (name 2) (type input))))
|
||||||
|
(libpart (lib SEN-13879) (part SEN-13879)
|
||||||
|
(fields
|
||||||
|
(field (name Reference) U)
|
||||||
|
(field (name Value) SEN-13879)
|
||||||
|
(field (name Footprint) SPARKFUN_SEN-13879)
|
||||||
|
(field (name Datasheet) "Load Cell Amp Hx711")
|
||||||
|
(field (name Field4) SparkFun)
|
||||||
|
(field (name Field5) Unavailable)
|
||||||
|
(field (name Field6) SEN-13879)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) None))
|
||||||
|
(pins
|
||||||
|
(pin (num 1) (name RED) (type BiDi))
|
||||||
|
(pin (num 2) (name BLK) (type BiDi))
|
||||||
|
(pin (num 3) (name WHT) (type input))
|
||||||
|
(pin (num 4) (name GRN) (type input))
|
||||||
|
(pin (num 5) (name YLW) (type BiDi))
|
||||||
|
(pin (num 6) (name GND) (type power_in))
|
||||||
|
(pin (num 7) (name CLK) (type input))
|
||||||
|
(pin (num 8) (name DAT) (type output))
|
||||||
|
(pin (num 9) (name VCC) (type power_in))
|
||||||
|
(pin (num 10) (name VDD) (type power_in))
|
||||||
|
(pin (num 11) (name B+) (type input))
|
||||||
|
(pin (num 12) (name B-) (type input))))
|
||||||
|
(libpart (lib T4145015051-001) (part T4145015051-001)
|
||||||
|
(fields
|
||||||
|
(field (name Reference) J)
|
||||||
|
(field (name Value) T4145015051-001)
|
||||||
|
(field (name Footprint) T4145015051-001)
|
||||||
|
(field (name Datasheet) "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P")
|
||||||
|
(field (name Field4) https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493)
|
||||||
|
(field (name Field5) "TE Connectivity")
|
||||||
|
(field (name Field6) Unavailable)
|
||||||
|
(field (name Field7) None)
|
||||||
|
(field (name Field8) T4145015051-001)
|
||||||
|
(field (name Field9) T4145015051-001)
|
||||||
|
(field (name Field10) None))
|
||||||
|
(pins
|
||||||
|
(pin (num P$1) (name 1) (type BiDi))
|
||||||
|
(pin (num P$2) (name 2) (type BiDi))
|
||||||
|
(pin (num P$3) (name 3) (type BiDi))
|
||||||
|
(pin (num P$4) (name 4) (type BiDi))
|
||||||
|
(pin (num P$5) (name 5) (type BiDi)))))
|
||||||
|
(libraries
|
||||||
|
(library (logical Connector)
|
||||||
|
(uri /usr/share/kicad/library/Connector.lib))
|
||||||
|
(library (logical Connector_Generic)
|
||||||
|
(uri /usr/share/kicad/library/Connector_Generic.lib))
|
||||||
|
(library (logical MiscellaneousDevices)
|
||||||
|
(uri /home/joerg/git-repos/KiCad-Libraries/symbols/MiscellaneousDevices.lib))
|
||||||
|
(library (logical SEN-13879)
|
||||||
|
(uri /home/joerg/Downloads/SEN-13879.lib))
|
||||||
|
(library (logical T4145015051-001)
|
||||||
|
(uri /home/joerg/Downloads/T4145015051-001.lib)))
|
||||||
|
(nets
|
||||||
|
(net (code 1) (name "Net-(J3-Pad1)")
|
||||||
|
(node (ref J3) (pin 1))
|
||||||
|
(node (ref U1) (pin 15)))
|
||||||
|
(net (code 2) (name "Net-(BAT1-Pad1)")
|
||||||
|
(node (ref SWITCH1) (pin 1))
|
||||||
|
(node (ref BAT1) (pin 1)))
|
||||||
|
(net (code 3) (name "Net-(SWITCH1-Pad2)")
|
||||||
|
(node (ref U1) (pin 17))
|
||||||
|
(node (ref SWITCH1) (pin 2)))
|
||||||
|
(net (code 4) (name "Net-(U1-Pad19)")
|
||||||
|
(node (ref U1) (pin 19)))
|
||||||
|
(net (code 5) (name "Net-(J3-Pad5)")
|
||||||
|
(node (ref J3) (pin 5))
|
||||||
|
(node (ref U1) (pin 16)))
|
||||||
|
(net (code 6) (name "Net-(J3-Pad3)")
|
||||||
|
(node (ref J3) (pin 3))
|
||||||
|
(node (ref U1) (pin 25)))
|
||||||
|
(net (code 7) (name "Net-(HX711-2-Pad4)")
|
||||||
|
(node (ref HX711-2) (pin 4))
|
||||||
|
(node (ref J2) (pin P$4)))
|
||||||
|
(net (code 8) (name "Net-(HX711-2-Pad1)")
|
||||||
|
(node (ref J2) (pin P$1))
|
||||||
|
(node (ref HX711-2) (pin 1)))
|
||||||
|
(net (code 9) (name "Net-(HX711-2-Pad2)")
|
||||||
|
(node (ref J2) (pin P$2))
|
||||||
|
(node (ref HX711-2) (pin 2)))
|
||||||
|
(net (code 10) (name "Net-(HX711-2-Pad3)")
|
||||||
|
(node (ref HX711-2) (pin 3))
|
||||||
|
(node (ref J2) (pin P$3)))
|
||||||
|
(net (code 11) (name "Net-(HX711-2-Pad5)")
|
||||||
|
(node (ref HX711-2) (pin 5))
|
||||||
|
(node (ref J2) (pin P$5)))
|
||||||
|
(net (code 12) (name "Net-(U1-Pad6)")
|
||||||
|
(node (ref U1) (pin 6)))
|
||||||
|
(net (code 13) (name "Net-(U1-Pad7)")
|
||||||
|
(node (ref U1) (pin 7)))
|
||||||
|
(net (code 14) (name "Net-(U1-Pad9)")
|
||||||
|
(node (ref U1) (pin 9)))
|
||||||
|
(net (code 15) (name "Net-(HX711-2-Pad8)")
|
||||||
|
(node (ref HX711-2) (pin 8))
|
||||||
|
(node (ref U1) (pin 21)))
|
||||||
|
(net (code 16) (name "Net-(J4-Pad1)")
|
||||||
|
(node (ref J4) (pin 1))
|
||||||
|
(node (ref U1) (pin 3)))
|
||||||
|
(net (code 17) (name "Net-(J4-Pad2)")
|
||||||
|
(node (ref J4) (pin 2))
|
||||||
|
(node (ref U1) (pin 2)))
|
||||||
|
(net (code 18) (name "Net-(U1-Pad5)")
|
||||||
|
(node (ref U1) (pin 5)))
|
||||||
|
(net (code 19) (name "Net-(U1-Pad23)")
|
||||||
|
(node (ref U1) (pin 23)))
|
||||||
|
(net (code 20) (name "Net-(J3-Pad4)")
|
||||||
|
(node (ref U1) (pin 24))
|
||||||
|
(node (ref J3) (pin 4)))
|
||||||
|
(net (code 21) (name "Net-(U1-Pad8)")
|
||||||
|
(node (ref U1) (pin 8)))
|
||||||
|
(net (code 22) (name "Net-(U1-Pad1)")
|
||||||
|
(node (ref U1) (pin 1)))
|
||||||
|
(net (code 23) (name "Net-(U1-Pad4)")
|
||||||
|
(node (ref U1) (pin 4)))
|
||||||
|
(net (code 24) (name "Net-(HX711-1-Pad7)")
|
||||||
|
(node (ref HX711-1) (pin 7))
|
||||||
|
(node (ref U1) (pin 12)))
|
||||||
|
(net (code 25) (name "Net-(U1-Pad14)")
|
||||||
|
(node (ref U1) (pin 14)))
|
||||||
|
(net (code 26) (name "Net-(U1-Pad20)")
|
||||||
|
(node (ref U1) (pin 20)))
|
||||||
|
(net (code 27) (name "Net-(U1-Pad22)")
|
||||||
|
(node (ref U1) (pin 22)))
|
||||||
|
(net (code 28) (name "Net-(U1-Pad26)")
|
||||||
|
(node (ref U1) (pin 26)))
|
||||||
|
(net (code 29) (name "Net-(U1-Pad27)")
|
||||||
|
(node (ref U1) (pin 27)))
|
||||||
|
(net (code 30) (name "Net-(U1-Pad28)")
|
||||||
|
(node (ref U1) (pin 28)))
|
||||||
|
(net (code 31) (name "Net-(BAT1-Pad2)")
|
||||||
|
(node (ref HX711-1) (pin 6))
|
||||||
|
(node (ref BAT1) (pin 2))
|
||||||
|
(node (ref J3) (pin 2))
|
||||||
|
(node (ref HX711-2) (pin 6))
|
||||||
|
(node (ref U1) (pin 13))
|
||||||
|
(node (ref J4) (pin 3)))
|
||||||
|
(net (code 32) (name "Net-(HX711-1-Pad10)")
|
||||||
|
(node (ref HX711-2) (pin 9))
|
||||||
|
(node (ref HX711-2) (pin 10))
|
||||||
|
(node (ref HX711-1) (pin 9))
|
||||||
|
(node (ref HX711-1) (pin 10))
|
||||||
|
(node (ref VOUT1) (pin 1)))
|
||||||
|
(net (code 33) (name "Net-(HX711-2-Pad11)")
|
||||||
|
(node (ref HX711-2) (pin 11)))
|
||||||
|
(net (code 34) (name "Net-(HX711-2-Pad12)")
|
||||||
|
(node (ref HX711-2) (pin 12)))
|
||||||
|
(net (code 35) (name "Net-(HX711-1-Pad3)")
|
||||||
|
(node (ref J1) (pin P$3))
|
||||||
|
(node (ref HX711-1) (pin 3)))
|
||||||
|
(net (code 36) (name "Net-(HX711-1-Pad4)")
|
||||||
|
(node (ref J1) (pin P$4))
|
||||||
|
(node (ref HX711-1) (pin 4)))
|
||||||
|
(net (code 37) (name "Net-(HX711-1-Pad5)")
|
||||||
|
(node (ref HX711-1) (pin 5))
|
||||||
|
(node (ref J1) (pin P$5)))
|
||||||
|
(net (code 38) (name "Net-(HX711-1-Pad8)")
|
||||||
|
(node (ref U1) (pin 11))
|
||||||
|
(node (ref HX711-1) (pin 8)))
|
||||||
|
(net (code 39) (name "Net-(HX711-1-Pad11)")
|
||||||
|
(node (ref HX711-1) (pin 11)))
|
||||||
|
(net (code 40) (name "Net-(HX711-1-Pad12)")
|
||||||
|
(node (ref HX711-1) (pin 12)))
|
||||||
|
(net (code 41) (name "Net-(HX711-1-Pad2)")
|
||||||
|
(node (ref HX711-1) (pin 2))
|
||||||
|
(node (ref J1) (pin P$2)))
|
||||||
|
(net (code 42) (name "Net-(HX711-1-Pad1)")
|
||||||
|
(node (ref HX711-1) (pin 1))
|
||||||
|
(node (ref J1) (pin P$1)))
|
||||||
|
(net (code 43) (name "Net-(HX711-2-Pad7)")
|
||||||
|
(node (ref HX711-2) (pin 7))
|
||||||
|
(node (ref U1) (pin 10)))
|
||||||
|
(net (code 44) (name "Net-(U1-Pad18)")
|
||||||
|
(node (ref U1) (pin 18)))))
|
||||||
|
|
@ -0,0 +1,248 @@
|
||||||
|
update=Mo 27 Mai 2019 17:30:58 CEST
|
||||||
|
version=1
|
||||||
|
last_client=kicad
|
||||||
|
[general]
|
||||||
|
version=1
|
||||||
|
RootSch=
|
||||||
|
BoardNm=
|
||||||
|
[cvpcb]
|
||||||
|
version=1
|
||||||
|
NetIExt=net
|
||||||
|
[eeschema]
|
||||||
|
version=1
|
||||||
|
LibDir=
|
||||||
|
[eeschema/libraries]
|
||||||
|
[schematic_editor]
|
||||||
|
version=1
|
||||||
|
PageLayoutDescrFile=empty.kicad_wks
|
||||||
|
PlotDirectoryName=
|
||||||
|
SubpartIdSeparator=0
|
||||||
|
SubpartFirstId=65
|
||||||
|
NetFmtName=Pcbnew
|
||||||
|
SpiceAjustPassiveValues=0
|
||||||
|
LabSize=50
|
||||||
|
ERC_TestSimilarLabels=1
|
||||||
|
[pcbnew]
|
||||||
|
version=1
|
||||||
|
PageLayoutDescrFile=
|
||||||
|
LastNetListRead=beieliscale-kicad.net
|
||||||
|
CopperLayerCount=2
|
||||||
|
BoardThickness=1.6
|
||||||
|
AllowMicroVias=0
|
||||||
|
AllowBlindVias=0
|
||||||
|
RequireCourtyardDefinitions=0
|
||||||
|
ProhibitOverlappingCourtyards=1
|
||||||
|
MinTrackWidth=0.2
|
||||||
|
MinViaDiameter=0.4
|
||||||
|
MinViaDrill=0.3
|
||||||
|
MinMicroViaDiameter=0.2
|
||||||
|
MinMicroViaDrill=0.09999999999999999
|
||||||
|
MinHoleToHole=0.25
|
||||||
|
TrackWidth1=0.25
|
||||||
|
ViaDiameter1=0.8
|
||||||
|
ViaDrill1=0.4
|
||||||
|
dPairWidth1=0.2
|
||||||
|
dPairGap1=0.25
|
||||||
|
dPairViaGap1=0.25
|
||||||
|
SilkLineWidth=0.15
|
||||||
|
SilkTextSizeV=1
|
||||||
|
SilkTextSizeH=1
|
||||||
|
SilkTextSizeThickness=0.15
|
||||||
|
SilkTextItalic=0
|
||||||
|
SilkTextUpright=1
|
||||||
|
CopperLineWidth=0.2
|
||||||
|
CopperTextSizeV=1.5
|
||||||
|
CopperTextSizeH=1.5
|
||||||
|
CopperTextThickness=0.3
|
||||||
|
CopperTextItalic=0
|
||||||
|
CopperTextUpright=1
|
||||||
|
EdgeCutLineWidth=0.15
|
||||||
|
CourtyardLineWidth=0.05
|
||||||
|
OthersLineWidth=0.15
|
||||||
|
OthersTextSizeV=1
|
||||||
|
OthersTextSizeH=1
|
||||||
|
OthersTextSizeThickness=0.15
|
||||||
|
OthersTextItalic=0
|
||||||
|
OthersTextUpright=1
|
||||||
|
SolderMaskClearance=0.051
|
||||||
|
SolderMaskMinWidth=0.25
|
||||||
|
SolderPasteClearance=0
|
||||||
|
SolderPasteRatio=0
|
||||||
|
[pcbnew/Layer.F.Cu]
|
||||||
|
Name=F.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.In1.Cu]
|
||||||
|
Name=In1.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In2.Cu]
|
||||||
|
Name=In2.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In3.Cu]
|
||||||
|
Name=In3.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In4.Cu]
|
||||||
|
Name=In4.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In5.Cu]
|
||||||
|
Name=In5.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In6.Cu]
|
||||||
|
Name=In6.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In7.Cu]
|
||||||
|
Name=In7.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In8.Cu]
|
||||||
|
Name=In8.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In9.Cu]
|
||||||
|
Name=In9.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In10.Cu]
|
||||||
|
Name=In10.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In11.Cu]
|
||||||
|
Name=In11.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In12.Cu]
|
||||||
|
Name=In12.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In13.Cu]
|
||||||
|
Name=In13.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In14.Cu]
|
||||||
|
Name=In14.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In15.Cu]
|
||||||
|
Name=In15.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In16.Cu]
|
||||||
|
Name=In16.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In17.Cu]
|
||||||
|
Name=In17.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In18.Cu]
|
||||||
|
Name=In18.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In19.Cu]
|
||||||
|
Name=In19.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In20.Cu]
|
||||||
|
Name=In20.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In21.Cu]
|
||||||
|
Name=In21.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In22.Cu]
|
||||||
|
Name=In22.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In23.Cu]
|
||||||
|
Name=In23.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In24.Cu]
|
||||||
|
Name=In24.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In25.Cu]
|
||||||
|
Name=In25.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In26.Cu]
|
||||||
|
Name=In26.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In27.Cu]
|
||||||
|
Name=In27.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In28.Cu]
|
||||||
|
Name=In28.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In29.Cu]
|
||||||
|
Name=In29.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.In30.Cu]
|
||||||
|
Name=In30.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Layer.B.Cu]
|
||||||
|
Name=B.Cu
|
||||||
|
Type=0
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.Adhes]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.Adhes]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.Paste]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.Paste]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.SilkS]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.SilkS]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.Mask]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.Mask]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Dwgs.User]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Cmts.User]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Eco1.User]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Eco2.User]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Edge.Cuts]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Margin]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.CrtYd]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.CrtYd]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.B.Fab]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.F.Fab]
|
||||||
|
Enabled=1
|
||||||
|
[pcbnew/Layer.Rescue]
|
||||||
|
Enabled=0
|
||||||
|
[pcbnew/Netclasses]
|
||||||
|
[pcbnew/Netclasses/Default]
|
||||||
|
Name=Default
|
||||||
|
Clearance=0.2
|
||||||
|
TrackWidth=0.25
|
||||||
|
ViaDiameter=0.8
|
||||||
|
ViaDrill=0.4
|
||||||
|
uViaDiameter=0.3
|
||||||
|
uViaDrill=0.1
|
||||||
|
dPairWidth=0.2
|
||||||
|
dPairGap=0.25
|
||||||
|
dPairViaGap=0.25
|
||||||
|
|
@ -0,0 +1,406 @@
|
||||||
|
EESchema Schematic File Version 4
|
||||||
|
LIBS:beieliscale-kicad-cache
|
||||||
|
EELAYER 29 0
|
||||||
|
EELAYER END
|
||||||
|
$Descr A4 11693 8268
|
||||||
|
encoding utf-8
|
||||||
|
Sheet 1 1
|
||||||
|
Title ""
|
||||||
|
Date ""
|
||||||
|
Rev ""
|
||||||
|
Comp ""
|
||||||
|
Comment1 ""
|
||||||
|
Comment2 ""
|
||||||
|
Comment3 ""
|
||||||
|
Comment4 ""
|
||||||
|
$EndDescr
|
||||||
|
$Comp
|
||||||
|
L SEN-13879:SEN-13879 HX711-1
|
||||||
|
U 1 1 5C8AE7C5
|
||||||
|
P 4550 3350
|
||||||
|
F 0 "HX711-1" H 4550 4117 50 0000 C CNN
|
||||||
|
F 1 "SEN-13879" H 4550 4026 50 0000 C CNN
|
||||||
|
F 2 "SPARKFUN_SEN-13879" H 4550 3350 50 0001 L BNN
|
||||||
|
F 3 "Load Cell Amp Hx711" H 4550 3350 50 0001 L BNN
|
||||||
|
F 4 "SparkFun" H 4550 3350 50 0001 L BNN "Field4"
|
||||||
|
F 5 "Unavailable" H 4550 3350 50 0001 L BNN "Field5"
|
||||||
|
F 6 "SEN-13879" H 4550 3350 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 4550 3350 50 0001 L BNN "Field7"
|
||||||
|
F 8 "None" H 4550 3350 50 0001 L BNN "Field8"
|
||||||
|
1 4550 3350
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6700 3550 6700 3150
|
||||||
|
Wire Wire Line
|
||||||
|
6700 3150 6850 3150
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3550 6700 3550
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3450 6750 3450
|
||||||
|
Wire Wire Line
|
||||||
|
6750 3450 6750 3250
|
||||||
|
Wire Wire Line
|
||||||
|
6750 3250 6850 3250
|
||||||
|
NoConn ~ 6850 2950
|
||||||
|
NoConn ~ 4050 3650
|
||||||
|
NoConn ~ 4050 3750
|
||||||
|
Wire Wire Line
|
||||||
|
5050 2950 5600 2950
|
||||||
|
Wire Wire Line
|
||||||
|
5600 2950 5600 2850
|
||||||
|
$Comp
|
||||||
|
L power:PWR_FLAG #FLG0101
|
||||||
|
U 1 1 5C8B848F
|
||||||
|
P 6000 2850
|
||||||
|
F 0 "#FLG0101" H 6000 2925 50 0001 C CNN
|
||||||
|
F 1 "PWR_FLAG" H 6000 3024 50 0000 C CNN
|
||||||
|
F 2 "" H 6000 2850 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 2850 50 0001 C CNN
|
||||||
|
1 6000 2850
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
5050 2850 5550 2850
|
||||||
|
Connection ~ 5600 2850
|
||||||
|
Wire Wire Line
|
||||||
|
5500 3850 5500 3050
|
||||||
|
NoConn ~ 8700 3050
|
||||||
|
NoConn ~ 8700 3250
|
||||||
|
NoConn ~ 8700 3650
|
||||||
|
NoConn ~ 8700 3750
|
||||||
|
NoConn ~ 8700 3850
|
||||||
|
$Comp
|
||||||
|
L power:PWR_FLAG #FLG0102
|
||||||
|
U 1 1 5C8C2453
|
||||||
|
P 5250 3850
|
||||||
|
F 0 "#FLG0102" H 5250 3925 50 0001 C CNN
|
||||||
|
F 1 "PWR_FLAG" H 5250 4024 50 0000 C CNN
|
||||||
|
F 2 "" H 5250 3850 50 0001 C CNN
|
||||||
|
F 3 "~" H 5250 3850 50 0001 C CNN
|
||||||
|
1 5250 3850
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Connection ~ 5250 3850
|
||||||
|
$Comp
|
||||||
|
L SEN-13879:SEN-13879 HX711-2
|
||||||
|
U 1 1 5C8CD302
|
||||||
|
P 4550 5100
|
||||||
|
F 0 "HX711-2" H 4550 5867 50 0000 C CNN
|
||||||
|
F 1 "SEN-13879" H 4550 5776 50 0000 C CNN
|
||||||
|
F 2 "SPARKFUN_SEN-13879" H 4550 5100 50 0001 L BNN
|
||||||
|
F 3 "Load Cell Amp Hx711" H 4550 5100 50 0001 L BNN
|
||||||
|
F 4 "SparkFun" H 4550 5100 50 0001 L BNN "Field4"
|
||||||
|
F 5 "Unavailable" H 4550 5100 50 0001 L BNN "Field5"
|
||||||
|
F 6 "SEN-13879" H 4550 5100 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 4550 5100 50 0001 L BNN "Field7"
|
||||||
|
F 8 "None" H 4550 5100 50 0001 L BNN "Field8"
|
||||||
|
1 4550 5100
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 4050 5400
|
||||||
|
NoConn ~ 4050 5500
|
||||||
|
Wire Wire Line
|
||||||
|
5050 4600 5600 4600
|
||||||
|
Wire Wire Line
|
||||||
|
5600 4600 5600 2950
|
||||||
|
Connection ~ 5600 2950
|
||||||
|
Wire Wire Line
|
||||||
|
5050 4700 5600 4700
|
||||||
|
Wire Wire Line
|
||||||
|
5600 4700 5600 4600
|
||||||
|
Connection ~ 5600 4600
|
||||||
|
Wire Wire Line
|
||||||
|
5050 5600 5250 5600
|
||||||
|
Wire Wire Line
|
||||||
|
5250 5600 5250 3850
|
||||||
|
Wire Wire Line
|
||||||
|
6650 5300 6650 3350
|
||||||
|
Wire Wire Line
|
||||||
|
6650 3350 6850 3350
|
||||||
|
Wire Wire Line
|
||||||
|
5050 5300 6650 5300
|
||||||
|
$Comp
|
||||||
|
L MiscellaneousDevices:ADAFRUIT_FEATHER U1
|
||||||
|
U 1 1 5C8BFC62
|
||||||
|
P 8950 3300
|
||||||
|
F 0 "U1" H 9128 3353 60 0000 L CNN
|
||||||
|
F 1 "MCCI 4610" H 9128 3247 60 0000 L CNN
|
||||||
|
F 2 "" H 9100 3100 60 0000 C CNN
|
||||||
|
F 3 "" H 9100 3100 60 0000 C CNN
|
||||||
|
1 8950 3300
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 8700 2850
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x02_Female BAT1
|
||||||
|
U 1 1 5C92F7C2
|
||||||
|
P 4350 1900
|
||||||
|
F 0 "BAT1" H 4244 1575 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x02_Female" H 4244 1666 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical" H 4350 1900 50 0001 C CNN
|
||||||
|
F 3 "~" H 4350 1900 50 0001 C CNN
|
||||||
|
1 4350 1900
|
||||||
|
-1 0 0 1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
8150 1900 8150 2750
|
||||||
|
Wire Wire Line
|
||||||
|
8150 2750 8700 2750
|
||||||
|
Wire Wire Line
|
||||||
|
5250 3850 5500 3850
|
||||||
|
$Comp
|
||||||
|
L T4145015051-001:T4145015051-001 J2
|
||||||
|
U 1 1 5CA65D1D
|
||||||
|
P 2950 5000
|
||||||
|
F 0 "J2" V 2483 5050 50 0000 C CNN
|
||||||
|
F 1 "T4145015051-001" V 2574 5050 50 0000 C CNN
|
||||||
|
F 2 "T4145015051-001" H 2950 5000 50 0001 L BNN
|
||||||
|
F 3 "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P" H 2950 5000 50 0001 L BNN
|
||||||
|
F 4 "https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493" H 2950 5000 50 0001 L BNN "Field4"
|
||||||
|
F 5 "TE Connectivity" H 2950 5000 50 0001 L BNN "Field5"
|
||||||
|
F 6 "Unavailable" H 2950 5000 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 2950 5000 50 0001 L BNN "Field7"
|
||||||
|
F 8 "T4145015051-001" H 2950 5000 50 0001 L BNN "Field8"
|
||||||
|
F 9 "T4145015051-001" H 2950 5000 50 0001 L BNN "Field9"
|
||||||
|
F 10 "None" H 2950 5000 50 0001 L BNN "Field10"
|
||||||
|
1 2950 5000
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
$Comp
|
||||||
|
L T4145015051-001:T4145015051-001 J1
|
||||||
|
U 1 1 5CA66C31
|
||||||
|
P 2950 3250
|
||||||
|
F 0 "J1" V 2483 3300 50 0000 C CNN
|
||||||
|
F 1 "T4145015051-001" V 2574 3300 50 0000 C CNN
|
||||||
|
F 2 "T4145015051-001" H 2950 3250 50 0001 L BNN
|
||||||
|
F 3 "Circular Metric Connectors; M12 R/A F PNLREAR STAMPED PIN A-CODE 5P" H 2950 3250 50 0001 L BNN
|
||||||
|
F 4 "https://www.te.com/usa-en/product-T4145015051-001.html?te_bu=Cor&te_type=disp&te_campaign=seda_glo_cor-seda-global-disp-prtnr-fy19-seda-model-bom-cta_sma-317_1&elqCampaignId=32493" H 2950 3250 50 0001 L BNN "Field4"
|
||||||
|
F 5 "TE Connectivity" H 2950 3250 50 0001 L BNN "Field5"
|
||||||
|
F 6 "Unavailable" H 2950 3250 50 0001 L BNN "Field6"
|
||||||
|
F 7 "None" H 2950 3250 50 0001 L BNN "Field7"
|
||||||
|
F 8 "T4145015051-001" H 2950 3250 50 0001 L BNN "Field8"
|
||||||
|
F 9 "T4145015051-001" H 2950 3250 50 0001 L BNN "Field9"
|
||||||
|
F 10 "None" H 2950 3250 50 0001 L BNN "Field10"
|
||||||
|
1 2950 3250
|
||||||
|
0 1 1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3050 3350 3050
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3150 3450 3150
|
||||||
|
Wire Wire Line
|
||||||
|
3450 3150 3450 3450
|
||||||
|
Wire Wire Line
|
||||||
|
3450 3450 3350 3450
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3250 3650 3250
|
||||||
|
Wire Wire Line
|
||||||
|
3650 3250 3650 3650
|
||||||
|
Wire Wire Line
|
||||||
|
3650 3650 2650 3650
|
||||||
|
Wire Wire Line
|
||||||
|
2650 3650 2650 3450
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3350 3750 3350
|
||||||
|
Wire Wire Line
|
||||||
|
3750 3350 3750 3800
|
||||||
|
Wire Wire Line
|
||||||
|
3750 3800 2450 3800
|
||||||
|
Wire Wire Line
|
||||||
|
2450 3800 2450 3050
|
||||||
|
Wire Wire Line
|
||||||
|
2450 3050 2650 3050
|
||||||
|
Wire Wire Line
|
||||||
|
4050 3450 3850 3450
|
||||||
|
Wire Wire Line
|
||||||
|
3850 3450 3850 3900
|
||||||
|
Wire Wire Line
|
||||||
|
3850 3900 3250 3900
|
||||||
|
Wire Wire Line
|
||||||
|
3250 3900 3250 3250
|
||||||
|
Wire Wire Line
|
||||||
|
4050 4800 3350 4800
|
||||||
|
Wire Wire Line
|
||||||
|
4050 4900 3500 4900
|
||||||
|
Wire Wire Line
|
||||||
|
3500 4900 3500 5200
|
||||||
|
Wire Wire Line
|
||||||
|
3500 5200 3350 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4050 5000 3600 5000
|
||||||
|
Wire Wire Line
|
||||||
|
3600 5000 3600 5400
|
||||||
|
Wire Wire Line
|
||||||
|
3600 5400 2500 5400
|
||||||
|
Wire Wire Line
|
||||||
|
2500 5400 2500 5200
|
||||||
|
Wire Wire Line
|
||||||
|
2500 5200 2650 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4050 5100 3700 5100
|
||||||
|
Wire Wire Line
|
||||||
|
3700 5100 3700 5550
|
||||||
|
Wire Wire Line
|
||||||
|
3700 5550 2400 5550
|
||||||
|
Wire Wire Line
|
||||||
|
2400 5550 2400 4800
|
||||||
|
Wire Wire Line
|
||||||
|
2400 4800 2650 4800
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5200 3750 5600
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5600 3250 5600
|
||||||
|
Wire Wire Line
|
||||||
|
3250 5600 3250 5000
|
||||||
|
Wire Wire Line
|
||||||
|
3750 5200 4050 5200
|
||||||
|
Wire Wire Line
|
||||||
|
4550 1800 5150 1800
|
||||||
|
Wire Wire Line
|
||||||
|
5050 3850 5150 3850
|
||||||
|
Wire Wire Line
|
||||||
|
5150 3850 5250 3850
|
||||||
|
Connection ~ 5150 3850
|
||||||
|
Wire Wire Line
|
||||||
|
5150 1800 5150 3850
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x02_Female SWITCH1
|
||||||
|
U 1 1 5CAD5AEF
|
||||||
|
P 6300 1700
|
||||||
|
F 0 "SWITCH1" H 6194 1375 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x02_Female" H 6194 1466 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical" H 6300 1700 50 0001 C CNN
|
||||||
|
F 3 "~" H 6300 1700 50 0001 C CNN
|
||||||
|
1 6300 1700
|
||||||
|
0 -1 -1 0
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6400 1900 8150 1900
|
||||||
|
Wire Wire Line
|
||||||
|
4550 1900 6300 1900
|
||||||
|
NoConn ~ 8700 2950
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x05_Female J3
|
||||||
|
U 1 1 5CBF85B5
|
||||||
|
P 6000 3850
|
||||||
|
F 0 "J3" H 6150 4050 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x05_Female" H 5950 4150 50 0000 C CNN
|
||||||
|
F 2 "Connector_JST:JST_PH_B5B-PH-K_1x05_P2.00mm_Vertical" H 6000 3850 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 3850 50 0001 C CNN
|
||||||
|
1 6000 3850
|
||||||
|
-1 0 0 1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6600 4050 6600 2850
|
||||||
|
Wire Wire Line
|
||||||
|
6600 2850 6850 2850
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4050 6600 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3950 6500 3950
|
||||||
|
Wire Wire Line
|
||||||
|
6500 3950 6500 3050
|
||||||
|
Wire Wire Line
|
||||||
|
5500 3050 6500 3050
|
||||||
|
Connection ~ 6500 3050
|
||||||
|
Wire Wire Line
|
||||||
|
6500 3050 6850 3050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3650 6400 3650
|
||||||
|
Wire Wire Line
|
||||||
|
6400 3650 6400 2750
|
||||||
|
Wire Wire Line
|
||||||
|
6400 2750 6850 2750
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3850 6400 3850
|
||||||
|
Wire Wire Line
|
||||||
|
6400 3850 6400 4450
|
||||||
|
Wire Wire Line
|
||||||
|
8500 4450 8500 3550
|
||||||
|
Wire Wire Line
|
||||||
|
8500 3550 8700 3550
|
||||||
|
Wire Wire Line
|
||||||
|
6200 3750 6550 3750
|
||||||
|
Wire Wire Line
|
||||||
|
6550 3750 6550 4350
|
||||||
|
Wire Wire Line
|
||||||
|
8400 4350 8400 3450
|
||||||
|
Wire Wire Line
|
||||||
|
8400 3450 8700 3450
|
||||||
|
Wire Wire Line
|
||||||
|
6550 4350 8400 4350
|
||||||
|
Wire Wire Line
|
||||||
|
6400 4450 8500 4450
|
||||||
|
NoConn ~ 6850 3550
|
||||||
|
$Comp
|
||||||
|
L MiscellaneousDevices:ADAFRUIT_FEATHER U1
|
||||||
|
U 2 1 5C8C025E
|
||||||
|
P 7100 3500
|
||||||
|
F 0 "U1" H 7278 3606 60 0000 L CNN
|
||||||
|
F 1 "MCCI 4610" H 7278 3500 60 0000 L CNN
|
||||||
|
F 2 "Modules:ADAFRUIT_FEATHER" H 7278 3394 60 0000 L CNN
|
||||||
|
F 3 "" H 7250 3300 60 0000 C CNN
|
||||||
|
2 7100 3500
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
NoConn ~ 6850 4250
|
||||||
|
NoConn ~ 6850 3950
|
||||||
|
NoConn ~ 6850 3850
|
||||||
|
NoConn ~ 6850 3750
|
||||||
|
NoConn ~ 6850 3650
|
||||||
|
NoConn ~ 6850 3450
|
||||||
|
Wire Wire Line
|
||||||
|
8600 5200 5050 5200
|
||||||
|
Wire Wire Line
|
||||||
|
8600 3150 8600 5200
|
||||||
|
Wire Wire Line
|
||||||
|
8600 3150 8700 3150
|
||||||
|
$Comp
|
||||||
|
L Connector:Conn_01x03_Male J4
|
||||||
|
U 1 1 5CFBD036
|
||||||
|
P 6000 4900
|
||||||
|
F 0 "J4" H 6108 5181 50 0000 C CNN
|
||||||
|
F 1 "Conn_01x03_Male" H 6108 5090 50 0000 C CNN
|
||||||
|
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" H 6000 4900 50 0001 C CNN
|
||||||
|
F 3 "~" H 6000 4900 50 0001 C CNN
|
||||||
|
1 6000 4900
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
6200 5600 6200 5000
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4800 6750 4800
|
||||||
|
Wire Wire Line
|
||||||
|
6750 4800 6750 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6750 4050 6850 4050
|
||||||
|
Wire Wire Line
|
||||||
|
6200 4900 6800 4900
|
||||||
|
Wire Wire Line
|
||||||
|
6800 4900 6800 4150
|
||||||
|
Wire Wire Line
|
||||||
|
6800 4150 6850 4150
|
||||||
|
NoConn ~ 8700 3350
|
||||||
|
Wire Wire Line
|
||||||
|
5250 5600 6200 5600
|
||||||
|
Connection ~ 5250 5600
|
||||||
|
Wire Wire Line
|
||||||
|
5600 2850 6000 2850
|
||||||
|
$Comp
|
||||||
|
L Connector_Generic:Conn_01x01 VOUT1
|
||||||
|
U 1 1 5CFF362B
|
||||||
|
P 5750 2300
|
||||||
|
F 0 "VOUT1" H 5830 2342 50 0000 L CNN
|
||||||
|
F 1 "Conn_01x01" H 5830 2251 50 0000 L CNN
|
||||||
|
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Vertical" H 5750 2300 50 0001 C CNN
|
||||||
|
F 3 "~" H 5750 2300 50 0001 C CNN
|
||||||
|
1 5750 2300
|
||||||
|
1 0 0 -1
|
||||||
|
$EndComp
|
||||||
|
Wire Wire Line
|
||||||
|
5550 2300 5550 2850
|
||||||
|
Connection ~ 5550 2850
|
||||||
|
Wire Wire Line
|
||||||
|
5550 2850 5600 2850
|
||||||
|
$EndSCHEMATC
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
(page_layout
|
||||||
|
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
|
||||||
|
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
|
||||||
|
(line (name segm1:Line) (start 0 0) (end 0 0))
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2-5.fc29*
|
||||||
|
G04 #@! TF.CreationDate,2019-03-22T17:39:01+01:00*
|
||||||
|
G04 #@! TF.ProjectId,beieliscale-kicad,62656965-6c69-4736-9361-6c652d6b6963,rev?*
|
||||||
|
G04 #@! TF.SameCoordinates,Original*
|
||||||
|
G04 #@! TF.FileFunction,Paste,Bot*
|
||||||
|
G04 #@! TF.FilePolarity,Positive*
|
||||||
|
%FSLAX46Y46*%
|
||||||
|
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
|
||||||
|
G04 Created by KiCad (PCBNEW 5.0.2-5.fc29) date Fr 22 Mär 2019 17:39:01 CET*
|
||||||
|
%MOMM*%
|
||||||
|
%LPD*%
|
||||||
|
G01*
|
||||||
|
G04 APERTURE LIST*
|
||||||
|
G04 APERTURE END LIST*
|
||||||
|
M02*
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2-5.fc29*
|
||||||
|
G04 #@! TF.CreationDate,2019-03-22T17:39:01+01:00*
|
||||||
|
G04 #@! TF.ProjectId,beieliscale-kicad,62656965-6c69-4736-9361-6c652d6b6963,rev?*
|
||||||
|
G04 #@! TF.SameCoordinates,Original*
|
||||||
|
G04 #@! TF.FileFunction,Legend,Bot*
|
||||||
|
G04 #@! TF.FilePolarity,Positive*
|
||||||
|
%FSLAX46Y46*%
|
||||||
|
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
|
||||||
|
G04 Created by KiCad (PCBNEW 5.0.2-5.fc29) date Fr 22 Mär 2019 17:39:01 CET*
|
||||||
|
%MOMM*%
|
||||||
|
%LPD*%
|
||||||
|
G01*
|
||||||
|
G04 APERTURE LIST*
|
||||||
|
G04 APERTURE END LIST*
|
||||||
|
M02*
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2-5.fc29*
|
||||||
|
G04 #@! TF.CreationDate,2019-03-22T17:39:01+01:00*
|
||||||
|
G04 #@! TF.ProjectId,beieliscale-kicad,62656965-6c69-4736-9361-6c652d6b6963,rev?*
|
||||||
|
G04 #@! TF.SameCoordinates,Original*
|
||||||
|
G04 #@! TF.FileFunction,Profile,NP*
|
||||||
|
%FSLAX46Y46*%
|
||||||
|
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
|
||||||
|
G04 Created by KiCad (PCBNEW 5.0.2-5.fc29) date Fr 22 Mär 2019 17:39:01 CET*
|
||||||
|
%MOMM*%
|
||||||
|
%LPD*%
|
||||||
|
G01*
|
||||||
|
G04 APERTURE LIST*
|
||||||
|
%ADD10C,0.150000*%
|
||||||
|
G04 #@! TA.AperFunction,NonConductor*
|
||||||
|
%ADD11C,0.100000*%
|
||||||
|
G04 #@! TD*
|
||||||
|
G04 #@! TA.AperFunction,NonConductor*
|
||||||
|
%ADD12C,0.000100*%
|
||||||
|
G04 #@! TD*
|
||||||
|
G04 APERTURE END LIST*
|
||||||
|
D10*
|
||||||
|
X74930000Y-49900000D02*
|
||||||
|
X74930000Y-99900000D01*
|
||||||
|
X194000000Y-49900000D02*
|
||||||
|
X74930000Y-49900000D01*
|
||||||
|
X194000000Y-99900000D02*
|
||||||
|
X194000000Y-49900000D01*
|
||||||
|
X74930000Y-99900000D02*
|
||||||
|
X194000000Y-99900000D01*
|
||||||
|
D11*
|
||||||
|
G04 #@! TO.C,J1*
|
||||||
|
X192765000Y-93180000D02*
|
||||||
|
X192765000Y-92180000D01*
|
||||||
|
X192765000Y-92180000D02*
|
||||||
|
X190565000Y-92180000D01*
|
||||||
|
X190565000Y-92180000D02*
|
||||||
|
X190565000Y-93180000D01*
|
||||||
|
X190565000Y-93180000D02*
|
||||||
|
X192765000Y-93180000D01*
|
||||||
|
X192765000Y-80380000D02*
|
||||||
|
X192765000Y-79380000D01*
|
||||||
|
X192765000Y-79380000D02*
|
||||||
|
X190565000Y-79380000D01*
|
||||||
|
X190565000Y-79380000D02*
|
||||||
|
X190565000Y-80380000D01*
|
||||||
|
X190565000Y-80380000D02*
|
||||||
|
X192765000Y-80380000D01*
|
||||||
|
G04 #@! TO.C,J2*
|
||||||
|
X78240000Y-92180000D02*
|
||||||
|
X76040000Y-92180000D01*
|
||||||
|
X78240000Y-93180000D02*
|
||||||
|
X78240000Y-92180000D01*
|
||||||
|
X76040000Y-93180000D02*
|
||||||
|
X78240000Y-93180000D01*
|
||||||
|
X76040000Y-92180000D02*
|
||||||
|
X76040000Y-93180000D01*
|
||||||
|
X78240000Y-79380000D02*
|
||||||
|
X76040000Y-79380000D01*
|
||||||
|
X78240000Y-80380000D02*
|
||||||
|
X78240000Y-79380000D01*
|
||||||
|
X76040000Y-80380000D02*
|
||||||
|
X78240000Y-80380000D01*
|
||||||
|
X76040000Y-79380000D02*
|
||||||
|
X76040000Y-80380000D01*
|
||||||
|
G04 #@! TO.C,J3*
|
||||||
|
X80090000Y-62685000D02*
|
||||||
|
X77390000Y-62685000D01*
|
||||||
|
X77390000Y-62685000D02*
|
||||||
|
G75*
|
||||||
|
G02X77390000Y-61685000I0J500000D01*
|
||||||
|
G01*
|
||||||
|
X77390000Y-61685000D02*
|
||||||
|
X80090000Y-61685000D01*
|
||||||
|
X80090000Y-61685000D02*
|
||||||
|
G75*
|
||||||
|
G02X80090000Y-62685000I0J-500000D01*
|
||||||
|
G01*
|
||||||
|
X80090000Y-71185000D02*
|
||||||
|
X77390000Y-71185000D01*
|
||||||
|
X77390000Y-71185000D02*
|
||||||
|
G75*
|
||||||
|
G02X77390000Y-70185000I0J500000D01*
|
||||||
|
G01*
|
||||||
|
X77390000Y-70185000D02*
|
||||||
|
X80090000Y-70185000D01*
|
||||||
|
X80090000Y-70185000D02*
|
||||||
|
G75*
|
||||||
|
G02X80090000Y-71185000I0J-500000D01*
|
||||||
|
G01*
|
||||||
|
D12*
|
||||||
|
X79890000Y-66435000D02*
|
||||||
|
G75*
|
||||||
|
G03X79890000Y-66435000I-350000J0D01*
|
||||||
|
G01*
|
||||||
|
X79890000Y-65135000D02*
|
||||||
|
G75*
|
||||||
|
G03X79890000Y-65135000I-350000J0D01*
|
||||||
|
G01*
|
||||||
|
X79890000Y-67735000D02*
|
||||||
|
G75*
|
||||||
|
G03X79890000Y-67735000I-350000J0D01*
|
||||||
|
G01*
|
||||||
|
X78290000Y-67085000D02*
|
||||||
|
G75*
|
||||||
|
G03X78290000Y-67085000I-350000J0D01*
|
||||||
|
G01*
|
||||||
|
X78290000Y-65785000D02*
|
||||||
|
G75*
|
||||||
|
G03X78290000Y-65785000I-350000J0D01*
|
||||||
|
G01*
|
||||||
|
G04 #@! TD*
|
||||||
|
M02*
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2-5.fc29*
|
||||||
|
G04 #@! TF.CreationDate,2019-03-22T17:39:01+01:00*
|
||||||
|
G04 #@! TF.ProjectId,beieliscale-kicad,62656965-6c69-4736-9361-6c652d6b6963,rev?*
|
||||||
|
G04 #@! TF.SameCoordinates,Original*
|
||||||
|
G04 #@! TF.FileFunction,Paste,Top*
|
||||||
|
G04 #@! TF.FilePolarity,Positive*
|
||||||
|
%FSLAX46Y46*%
|
||||||
|
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
|
||||||
|
G04 Created by KiCad (PCBNEW 5.0.2-5.fc29) date Fr 22 Mär 2019 17:39:01 CET*
|
||||||
|
%MOMM*%
|
||||||
|
%LPD*%
|
||||||
|
G01*
|
||||||
|
G04 APERTURE LIST*
|
||||||
|
G04 APERTURE END LIST*
|
||||||
|
M02*
|
||||||
|
|
@ -0,0 +1,912 @@
|
||||||
|
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2-5.fc29*
|
||||||
|
G04 #@! TF.CreationDate,2019-03-22T17:39:01+01:00*
|
||||||
|
G04 #@! TF.ProjectId,beieliscale-kicad,62656965-6c69-4736-9361-6c652d6b6963,rev?*
|
||||||
|
G04 #@! TF.SameCoordinates,Original*
|
||||||
|
G04 #@! TF.FileFunction,Legend,Top*
|
||||||
|
G04 #@! TF.FilePolarity,Positive*
|
||||||
|
%FSLAX46Y46*%
|
||||||
|
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
|
||||||
|
G04 Created by KiCad (PCBNEW 5.0.2-5.fc29) date Fr 22 Mär 2019 17:39:01 CET*
|
||||||
|
%MOMM*%
|
||||||
|
%LPD*%
|
||||||
|
G01*
|
||||||
|
G04 APERTURE LIST*
|
||||||
|
%ADD10C,0.200000*%
|
||||||
|
%ADD11C,0.150000*%
|
||||||
|
%ADD12C,0.127000*%
|
||||||
|
%ADD13C,0.300000*%
|
||||||
|
%ADD14C,0.100000*%
|
||||||
|
%ADD15C,0.120000*%
|
||||||
|
G04 APERTURE END LIST*
|
||||||
|
D10*
|
||||||
|
X123240952Y-54632380D02*
|
||||||
|
X123240952Y-53965714D01*
|
||||||
|
X123240952Y-54060952D02*
|
||||||
|
X123288571Y-54013333D01*
|
||||||
|
X123383809Y-53965714D01*
|
||||||
|
X123526666Y-53965714D01*
|
||||||
|
X123621904Y-54013333D01*
|
||||||
|
X123669523Y-54108571D01*
|
||||||
|
X123669523Y-54632380D01*
|
||||||
|
X123669523Y-54108571D02*
|
||||||
|
X123717142Y-54013333D01*
|
||||||
|
X123812380Y-53965714D01*
|
||||||
|
X123955238Y-53965714D01*
|
||||||
|
X124050476Y-54013333D01*
|
||||||
|
X124098095Y-54108571D01*
|
||||||
|
X124098095Y-54632380D01*
|
||||||
|
X124574285Y-54632380D02*
|
||||||
|
X124574285Y-53965714D01*
|
||||||
|
X124574285Y-53632380D02*
|
||||||
|
X124526666Y-53680000D01*
|
||||||
|
X124574285Y-53727619D01*
|
||||||
|
X124621904Y-53680000D01*
|
||||||
|
X124574285Y-53632380D01*
|
||||||
|
X124574285Y-53727619D01*
|
||||||
|
X125050476Y-53965714D02*
|
||||||
|
X125050476Y-54632380D01*
|
||||||
|
X125050476Y-54060952D02*
|
||||||
|
X125098095Y-54013333D01*
|
||||||
|
X125193333Y-53965714D01*
|
||||||
|
X125336190Y-53965714D01*
|
||||||
|
X125431428Y-54013333D01*
|
||||||
|
X125479047Y-54108571D01*
|
||||||
|
X125479047Y-54632380D01*
|
||||||
|
X125955238Y-54632380D02*
|
||||||
|
X125955238Y-53965714D01*
|
||||||
|
X125955238Y-53632380D02*
|
||||||
|
X125907619Y-53680000D01*
|
||||||
|
X125955238Y-53727619D01*
|
||||||
|
X126002857Y-53680000D01*
|
||||||
|
X125955238Y-53632380D01*
|
||||||
|
X125955238Y-53727619D01*
|
||||||
|
X126431428Y-54251428D02*
|
||||||
|
X127193333Y-54251428D01*
|
||||||
|
X127669523Y-54632380D02*
|
||||||
|
X127669523Y-53632380D01*
|
||||||
|
X127669523Y-54013333D02*
|
||||||
|
X127764761Y-53965714D01*
|
||||||
|
X127955238Y-53965714D01*
|
||||||
|
X128050476Y-54013333D01*
|
||||||
|
X128098095Y-54060952D01*
|
||||||
|
X128145714Y-54156190D01*
|
||||||
|
X128145714Y-54441904D01*
|
||||||
|
X128098095Y-54537142D01*
|
||||||
|
X128050476Y-54584761D01*
|
||||||
|
X127955238Y-54632380D01*
|
||||||
|
X127764761Y-54632380D01*
|
||||||
|
X127669523Y-54584761D01*
|
||||||
|
X128955238Y-54584761D02*
|
||||||
|
X128860000Y-54632380D01*
|
||||||
|
X128669523Y-54632380D01*
|
||||||
|
X128574285Y-54584761D01*
|
||||||
|
X128526666Y-54489523D01*
|
||||||
|
X128526666Y-54108571D01*
|
||||||
|
X128574285Y-54013333D01*
|
||||||
|
X128669523Y-53965714D01*
|
||||||
|
X128860000Y-53965714D01*
|
||||||
|
X128955238Y-54013333D01*
|
||||||
|
X129002857Y-54108571D01*
|
||||||
|
X129002857Y-54203809D01*
|
||||||
|
X128526666Y-54299047D01*
|
||||||
|
X129431428Y-54632380D02*
|
||||||
|
X129431428Y-53965714D01*
|
||||||
|
X129431428Y-53632380D02*
|
||||||
|
X129383809Y-53680000D01*
|
||||||
|
X129431428Y-53727619D01*
|
||||||
|
X129479047Y-53680000D01*
|
||||||
|
X129431428Y-53632380D01*
|
||||||
|
X129431428Y-53727619D01*
|
||||||
|
X130288571Y-54584761D02*
|
||||||
|
X130193333Y-54632380D01*
|
||||||
|
X130002857Y-54632380D01*
|
||||||
|
X129907619Y-54584761D01*
|
||||||
|
X129860000Y-54489523D01*
|
||||||
|
X129860000Y-54108571D01*
|
||||||
|
X129907619Y-54013333D01*
|
||||||
|
X130002857Y-53965714D01*
|
||||||
|
X130193333Y-53965714D01*
|
||||||
|
X130288571Y-54013333D01*
|
||||||
|
X130336190Y-54108571D01*
|
||||||
|
X130336190Y-54203809D01*
|
||||||
|
X129860000Y-54299047D01*
|
||||||
|
X130907619Y-54632380D02*
|
||||||
|
X130812380Y-54584761D01*
|
||||||
|
X130764761Y-54489523D01*
|
||||||
|
X130764761Y-53632380D01*
|
||||||
|
X131288571Y-54632380D02*
|
||||||
|
X131288571Y-53965714D01*
|
||||||
|
X131288571Y-53632380D02*
|
||||||
|
X131240952Y-53680000D01*
|
||||||
|
X131288571Y-53727619D01*
|
||||||
|
X131336190Y-53680000D01*
|
||||||
|
X131288571Y-53632380D01*
|
||||||
|
X131288571Y-53727619D01*
|
||||||
|
X131764761Y-54537142D02*
|
||||||
|
X131812380Y-54584761D01*
|
||||||
|
X131764761Y-54632380D01*
|
||||||
|
X131717142Y-54584761D01*
|
||||||
|
X131764761Y-54537142D01*
|
||||||
|
X131764761Y-54632380D01*
|
||||||
|
X132669523Y-54584761D02*
|
||||||
|
X132574285Y-54632380D01*
|
||||||
|
X132383809Y-54632380D01*
|
||||||
|
X132288571Y-54584761D01*
|
||||||
|
X132240952Y-54537142D01*
|
||||||
|
X132193333Y-54441904D01*
|
||||||
|
X132193333Y-54156190D01*
|
||||||
|
X132240952Y-54060952D01*
|
||||||
|
X132288571Y-54013333D01*
|
||||||
|
X132383809Y-53965714D01*
|
||||||
|
X132574285Y-53965714D01*
|
||||||
|
X132669523Y-54013333D01*
|
||||||
|
X133098095Y-54632380D02*
|
||||||
|
X133098095Y-53632380D01*
|
||||||
|
X133526666Y-54632380D02*
|
||||||
|
X133526666Y-54108571D01*
|
||||||
|
X133479047Y-54013333D01*
|
||||||
|
X133383809Y-53965714D01*
|
||||||
|
X133240952Y-53965714D01*
|
||||||
|
X133145714Y-54013333D01*
|
||||||
|
X133098095Y-54060952D01*
|
||||||
|
X134764761Y-54251428D02*
|
||||||
|
X135526666Y-54251428D01*
|
||||||
|
X137098095Y-54108571D02*
|
||||||
|
X137240952Y-54156190D01*
|
||||||
|
X137288571Y-54203809D01*
|
||||||
|
X137336190Y-54299047D01*
|
||||||
|
X137336190Y-54441904D01*
|
||||||
|
X137288571Y-54537142D01*
|
||||||
|
X137240952Y-54584761D01*
|
||||||
|
X137145714Y-54632380D01*
|
||||||
|
X136764761Y-54632380D01*
|
||||||
|
X136764761Y-53632380D01*
|
||||||
|
X137098095Y-53632380D01*
|
||||||
|
X137193333Y-53680000D01*
|
||||||
|
X137240952Y-53727619D01*
|
||||||
|
X137288571Y-53822857D01*
|
||||||
|
X137288571Y-53918095D01*
|
||||||
|
X137240952Y-54013333D01*
|
||||||
|
X137193333Y-54060952D01*
|
||||||
|
X137098095Y-54108571D01*
|
||||||
|
X136764761Y-54108571D01*
|
||||||
|
X138145714Y-54584761D02*
|
||||||
|
X138050476Y-54632380D01*
|
||||||
|
X137860000Y-54632380D01*
|
||||||
|
X137764761Y-54584761D01*
|
||||||
|
X137717142Y-54489523D01*
|
||||||
|
X137717142Y-54108571D01*
|
||||||
|
X137764761Y-54013333D01*
|
||||||
|
X137860000Y-53965714D01*
|
||||||
|
X138050476Y-53965714D01*
|
||||||
|
X138145714Y-54013333D01*
|
||||||
|
X138193333Y-54108571D01*
|
||||||
|
X138193333Y-54203809D01*
|
||||||
|
X137717142Y-54299047D01*
|
||||||
|
X138621904Y-54632380D02*
|
||||||
|
X138621904Y-53965714D01*
|
||||||
|
X138621904Y-53632380D02*
|
||||||
|
X138574285Y-53680000D01*
|
||||||
|
X138621904Y-53727619D01*
|
||||||
|
X138669523Y-53680000D01*
|
||||||
|
X138621904Y-53632380D01*
|
||||||
|
X138621904Y-53727619D01*
|
||||||
|
X139479047Y-54584761D02*
|
||||||
|
X139383809Y-54632380D01*
|
||||||
|
X139193333Y-54632380D01*
|
||||||
|
X139098095Y-54584761D01*
|
||||||
|
X139050476Y-54489523D01*
|
||||||
|
X139050476Y-54108571D01*
|
||||||
|
X139098095Y-54013333D01*
|
||||||
|
X139193333Y-53965714D01*
|
||||||
|
X139383809Y-53965714D01*
|
||||||
|
X139479047Y-54013333D01*
|
||||||
|
X139526666Y-54108571D01*
|
||||||
|
X139526666Y-54203809D01*
|
||||||
|
X139050476Y-54299047D01*
|
||||||
|
X140098095Y-54632380D02*
|
||||||
|
X140002857Y-54584761D01*
|
||||||
|
X139955238Y-54489523D01*
|
||||||
|
X139955238Y-53632380D01*
|
||||||
|
X140479047Y-54632380D02*
|
||||||
|
X140479047Y-53965714D01*
|
||||||
|
X140479047Y-53632380D02*
|
||||||
|
X140431428Y-53680000D01*
|
||||||
|
X140479047Y-53727619D01*
|
||||||
|
X140526666Y-53680000D01*
|
||||||
|
X140479047Y-53632380D01*
|
||||||
|
X140479047Y-53727619D01*
|
||||||
|
X140907619Y-54584761D02*
|
||||||
|
X141050476Y-54632380D01*
|
||||||
|
X141288571Y-54632380D01*
|
||||||
|
X141383809Y-54584761D01*
|
||||||
|
X141431428Y-54537142D01*
|
||||||
|
X141479047Y-54441904D01*
|
||||||
|
X141479047Y-54346666D01*
|
||||||
|
X141431428Y-54251428D01*
|
||||||
|
X141383809Y-54203809D01*
|
||||||
|
X141288571Y-54156190D01*
|
||||||
|
X141098095Y-54108571D01*
|
||||||
|
X141002857Y-54060952D01*
|
||||||
|
X140955238Y-54013333D01*
|
||||||
|
X140907619Y-53918095D01*
|
||||||
|
X140907619Y-53822857D01*
|
||||||
|
X140955238Y-53727619D01*
|
||||||
|
X141002857Y-53680000D01*
|
||||||
|
X141098095Y-53632380D01*
|
||||||
|
X141336190Y-53632380D01*
|
||||||
|
X141479047Y-53680000D01*
|
||||||
|
X142336190Y-54584761D02*
|
||||||
|
X142240952Y-54632380D01*
|
||||||
|
X142050476Y-54632380D01*
|
||||||
|
X141955238Y-54584761D01*
|
||||||
|
X141907619Y-54537142D01*
|
||||||
|
X141860000Y-54441904D01*
|
||||||
|
X141860000Y-54156190D01*
|
||||||
|
X141907619Y-54060952D01*
|
||||||
|
X141955238Y-54013333D01*
|
||||||
|
X142050476Y-53965714D01*
|
||||||
|
X142240952Y-53965714D01*
|
||||||
|
X142336190Y-54013333D01*
|
||||||
|
X143193333Y-54632380D02*
|
||||||
|
X143193333Y-54108571D01*
|
||||||
|
X143145714Y-54013333D01*
|
||||||
|
X143050476Y-53965714D01*
|
||||||
|
X142860000Y-53965714D01*
|
||||||
|
X142764761Y-54013333D01*
|
||||||
|
X143193333Y-54584761D02*
|
||||||
|
X143098095Y-54632380D01*
|
||||||
|
X142860000Y-54632380D01*
|
||||||
|
X142764761Y-54584761D01*
|
||||||
|
X142717142Y-54489523D01*
|
||||||
|
X142717142Y-54394285D01*
|
||||||
|
X142764761Y-54299047D01*
|
||||||
|
X142860000Y-54251428D01*
|
||||||
|
X143098095Y-54251428D01*
|
||||||
|
X143193333Y-54203809D01*
|
||||||
|
X143812380Y-54632380D02*
|
||||||
|
X143717142Y-54584761D01*
|
||||||
|
X143669523Y-54489523D01*
|
||||||
|
X143669523Y-53632380D01*
|
||||||
|
X144574285Y-54584761D02*
|
||||||
|
X144479047Y-54632380D01*
|
||||||
|
X144288571Y-54632380D01*
|
||||||
|
X144193333Y-54584761D01*
|
||||||
|
X144145714Y-54489523D01*
|
||||||
|
X144145714Y-54108571D01*
|
||||||
|
X144193333Y-54013333D01*
|
||||||
|
X144288571Y-53965714D01*
|
||||||
|
X144479047Y-53965714D01*
|
||||||
|
X144574285Y-54013333D01*
|
||||||
|
X144621904Y-54108571D01*
|
||||||
|
X144621904Y-54203809D01*
|
||||||
|
X144145714Y-54299047D01*
|
||||||
|
X145812380Y-54632380D02*
|
||||||
|
X145812380Y-53632380D01*
|
||||||
|
X145812380Y-54013333D02*
|
||||||
|
X145907619Y-53965714D01*
|
||||||
|
X146098095Y-53965714D01*
|
||||||
|
X146193333Y-54013333D01*
|
||||||
|
X146240952Y-54060952D01*
|
||||||
|
X146288571Y-54156190D01*
|
||||||
|
X146288571Y-54441904D01*
|
||||||
|
X146240952Y-54537142D01*
|
||||||
|
X146193333Y-54584761D01*
|
||||||
|
X146098095Y-54632380D01*
|
||||||
|
X145907619Y-54632380D01*
|
||||||
|
X145812380Y-54584761D01*
|
||||||
|
X146621904Y-53965714D02*
|
||||||
|
X146860000Y-54632380D01*
|
||||||
|
X147098095Y-53965714D02*
|
||||||
|
X146860000Y-54632380D01*
|
||||||
|
X146764761Y-54870476D01*
|
||||||
|
X146717142Y-54918095D01*
|
||||||
|
X146621904Y-54965714D01*
|
||||||
|
X148240952Y-53965714D02*
|
||||||
|
X148240952Y-54632380D01*
|
||||||
|
X148240952Y-54060952D02*
|
||||||
|
X148288571Y-54013333D01*
|
||||||
|
X148383809Y-53965714D01*
|
||||||
|
X148526666Y-53965714D01*
|
||||||
|
X148621904Y-54013333D01*
|
||||||
|
X148669523Y-54108571D01*
|
||||||
|
X148669523Y-54632380D01*
|
||||||
|
X149145714Y-54632380D02*
|
||||||
|
X149145714Y-53632380D01*
|
||||||
|
X149145714Y-54013333D02*
|
||||||
|
X149240952Y-53965714D01*
|
||||||
|
X149431428Y-53965714D01*
|
||||||
|
X149526666Y-54013333D01*
|
||||||
|
X149574285Y-54060952D01*
|
||||||
|
X149621904Y-54156190D01*
|
||||||
|
X149621904Y-54441904D01*
|
||||||
|
X149574285Y-54537142D01*
|
||||||
|
X149526666Y-54584761D01*
|
||||||
|
X149431428Y-54632380D01*
|
||||||
|
X149240952Y-54632380D01*
|
||||||
|
X149145714Y-54584761D01*
|
||||||
|
X150050476Y-54632380D02*
|
||||||
|
X150050476Y-53965714D01*
|
||||||
|
X150050476Y-53632380D02*
|
||||||
|
X150002857Y-53680000D01*
|
||||||
|
X150050476Y-53727619D01*
|
||||||
|
X150098095Y-53680000D01*
|
||||||
|
X150050476Y-53632380D01*
|
||||||
|
X150050476Y-53727619D01*
|
||||||
|
X150383809Y-53965714D02*
|
||||||
|
X150764761Y-53965714D01*
|
||||||
|
X150526666Y-53632380D02*
|
||||||
|
X150526666Y-54489523D01*
|
||||||
|
X150574285Y-54584761D01*
|
||||||
|
X150669523Y-54632380D01*
|
||||||
|
X150764761Y-54632380D01*
|
||||||
|
X151860000Y-54632380D02*
|
||||||
|
X151860000Y-53632380D01*
|
||||||
|
X152336190Y-53965714D02*
|
||||||
|
X152336190Y-54632380D01*
|
||||||
|
X152336190Y-54060952D02*
|
||||||
|
X152383809Y-54013333D01*
|
||||||
|
X152479047Y-53965714D01*
|
||||||
|
X152621904Y-53965714D01*
|
||||||
|
X152717142Y-54013333D01*
|
||||||
|
X152764761Y-54108571D01*
|
||||||
|
X152764761Y-54632380D01*
|
||||||
|
X153098095Y-53965714D02*
|
||||||
|
X153479047Y-53965714D01*
|
||||||
|
X153240952Y-54632380D02*
|
||||||
|
X153240952Y-53775238D01*
|
||||||
|
X153288571Y-53680000D01*
|
||||||
|
X153383809Y-53632380D01*
|
||||||
|
X153479047Y-53632380D01*
|
||||||
|
X153955238Y-54632380D02*
|
||||||
|
X153860000Y-54584761D01*
|
||||||
|
X153812380Y-54537142D01*
|
||||||
|
X153764761Y-54441904D01*
|
||||||
|
X153764761Y-54156190D01*
|
||||||
|
X153812380Y-54060952D01*
|
||||||
|
X153860000Y-54013333D01*
|
||||||
|
X153955238Y-53965714D01*
|
||||||
|
X154098095Y-53965714D01*
|
||||||
|
X154193333Y-54013333D01*
|
||||||
|
X154240952Y-54060952D01*
|
||||||
|
X154288571Y-54156190D01*
|
||||||
|
X154288571Y-54441904D01*
|
||||||
|
X154240952Y-54537142D01*
|
||||||
|
X154193333Y-54584761D01*
|
||||||
|
X154098095Y-54632380D01*
|
||||||
|
X153955238Y-54632380D01*
|
||||||
|
X154717142Y-54632380D02*
|
||||||
|
X154717142Y-53965714D01*
|
||||||
|
X154717142Y-54156190D02*
|
||||||
|
X154764761Y-54060952D01*
|
||||||
|
X154812380Y-54013333D01*
|
||||||
|
X154907619Y-53965714D01*
|
||||||
|
X155002857Y-53965714D01*
|
||||||
|
X155336190Y-54632380D02*
|
||||||
|
X155336190Y-53965714D01*
|
||||||
|
X155336190Y-54060952D02*
|
||||||
|
X155383809Y-54013333D01*
|
||||||
|
X155479047Y-53965714D01*
|
||||||
|
X155621904Y-53965714D01*
|
||||||
|
X155717142Y-54013333D01*
|
||||||
|
X155764761Y-54108571D01*
|
||||||
|
X155764761Y-54632380D01*
|
||||||
|
X155764761Y-54108571D02*
|
||||||
|
X155812380Y-54013333D01*
|
||||||
|
X155907619Y-53965714D01*
|
||||||
|
X156050476Y-53965714D01*
|
||||||
|
X156145714Y-54013333D01*
|
||||||
|
X156193333Y-54108571D01*
|
||||||
|
X156193333Y-54632380D01*
|
||||||
|
X157098095Y-54632380D02*
|
||||||
|
X157098095Y-54108571D01*
|
||||||
|
X157050476Y-54013333D01*
|
||||||
|
X156955238Y-53965714D01*
|
||||||
|
X156764761Y-53965714D01*
|
||||||
|
X156669523Y-54013333D01*
|
||||||
|
X157098095Y-54584761D02*
|
||||||
|
X157002857Y-54632380D01*
|
||||||
|
X156764761Y-54632380D01*
|
||||||
|
X156669523Y-54584761D01*
|
||||||
|
X156621904Y-54489523D01*
|
||||||
|
X156621904Y-54394285D01*
|
||||||
|
X156669523Y-54299047D01*
|
||||||
|
X156764761Y-54251428D01*
|
||||||
|
X157002857Y-54251428D01*
|
||||||
|
X157098095Y-54203809D01*
|
||||||
|
X157431428Y-53965714D02*
|
||||||
|
X157812380Y-53965714D01*
|
||||||
|
X157574285Y-53632380D02*
|
||||||
|
X157574285Y-54489523D01*
|
||||||
|
X157621904Y-54584761D01*
|
||||||
|
X157717142Y-54632380D01*
|
||||||
|
X157812380Y-54632380D01*
|
||||||
|
X158145714Y-54632380D02*
|
||||||
|
X158145714Y-53965714D01*
|
||||||
|
X158145714Y-53632380D02*
|
||||||
|
X158098095Y-53680000D01*
|
||||||
|
X158145714Y-53727619D01*
|
||||||
|
X158193333Y-53680000D01*
|
||||||
|
X158145714Y-53632380D01*
|
||||||
|
X158145714Y-53727619D01*
|
||||||
|
X158621904Y-54632380D02*
|
||||||
|
X158621904Y-53632380D01*
|
||||||
|
X158717142Y-54251428D02*
|
||||||
|
X159002857Y-54632380D01*
|
||||||
|
X159002857Y-53965714D02*
|
||||||
|
X158621904Y-54346666D01*
|
||||||
|
X160717142Y-53680000D02*
|
||||||
|
X160621904Y-53632380D01*
|
||||||
|
X160479047Y-53632380D01*
|
||||||
|
X160336190Y-53680000D01*
|
||||||
|
X160240952Y-53775238D01*
|
||||||
|
X160193333Y-53870476D01*
|
||||||
|
X160145714Y-54060952D01*
|
||||||
|
X160145714Y-54203809D01*
|
||||||
|
X160193333Y-54394285D01*
|
||||||
|
X160240952Y-54489523D01*
|
||||||
|
X160336190Y-54584761D01*
|
||||||
|
X160479047Y-54632380D01*
|
||||||
|
X160574285Y-54632380D01*
|
||||||
|
X160717142Y-54584761D01*
|
||||||
|
X160764761Y-54537142D01*
|
||||||
|
X160764761Y-54203809D01*
|
||||||
|
X160574285Y-54203809D01*
|
||||||
|
X161193333Y-54632380D02*
|
||||||
|
X161193333Y-53965714D01*
|
||||||
|
X161193333Y-54060952D02*
|
||||||
|
X161240952Y-54013333D01*
|
||||||
|
X161336190Y-53965714D01*
|
||||||
|
X161479047Y-53965714D01*
|
||||||
|
X161574285Y-54013333D01*
|
||||||
|
X161621904Y-54108571D01*
|
||||||
|
X161621904Y-54632380D01*
|
||||||
|
X161621904Y-54108571D02*
|
||||||
|
X161669523Y-54013333D01*
|
||||||
|
X161764761Y-53965714D01*
|
||||||
|
X161907619Y-53965714D01*
|
||||||
|
X162002857Y-54013333D01*
|
||||||
|
X162050476Y-54108571D01*
|
||||||
|
X162050476Y-54632380D01*
|
||||||
|
X162526666Y-54632380D02*
|
||||||
|
X162526666Y-53632380D01*
|
||||||
|
X162526666Y-54013333D02*
|
||||||
|
X162621904Y-53965714D01*
|
||||||
|
X162812380Y-53965714D01*
|
||||||
|
X162907619Y-54013333D01*
|
||||||
|
X162955238Y-54060952D01*
|
||||||
|
X163002857Y-54156190D01*
|
||||||
|
X163002857Y-54441904D01*
|
||||||
|
X162955238Y-54537142D01*
|
||||||
|
X162907619Y-54584761D01*
|
||||||
|
X162812380Y-54632380D01*
|
||||||
|
X162621904Y-54632380D01*
|
||||||
|
X162526666Y-54584761D01*
|
||||||
|
X163431428Y-54632380D02*
|
||||||
|
X163431428Y-53632380D01*
|
||||||
|
X163431428Y-54108571D02*
|
||||||
|
X164002857Y-54108571D01*
|
||||||
|
X164002857Y-54632380D02*
|
||||||
|
X164002857Y-53632380D01*
|
||||||
|
X165240952Y-54251428D02*
|
||||||
|
X166002857Y-54251428D01*
|
||||||
|
X167145714Y-53965714D02*
|
||||||
|
X167383809Y-54632380D01*
|
||||||
|
X167621904Y-53965714D01*
|
||||||
|
X168526666Y-54632380D02*
|
||||||
|
X167955238Y-54632380D01*
|
||||||
|
X168240952Y-54632380D02*
|
||||||
|
X168240952Y-53632380D01*
|
||||||
|
X168145714Y-53775238D01*
|
||||||
|
X168050476Y-53870476D01*
|
||||||
|
X167955238Y-53918095D01*
|
||||||
|
X168955238Y-54537142D02*
|
||||||
|
X169002857Y-54584761D01*
|
||||||
|
X168955238Y-54632380D01*
|
||||||
|
X168907619Y-54584761D01*
|
||||||
|
X168955238Y-54537142D01*
|
||||||
|
X168955238Y-54632380D01*
|
||||||
|
X169955238Y-54632380D02*
|
||||||
|
X169383809Y-54632380D01*
|
||||||
|
X169669523Y-54632380D02*
|
||||||
|
X169669523Y-53632380D01*
|
||||||
|
X169574285Y-53775238D01*
|
||||||
|
X169479047Y-53870476D01*
|
||||||
|
X169383809Y-53918095D01*
|
||||||
|
X171145714Y-54251428D02*
|
||||||
|
X171907619Y-54251428D01*
|
||||||
|
X173098095Y-53727619D02*
|
||||||
|
X173145714Y-53680000D01*
|
||||||
|
X173240952Y-53632380D01*
|
||||||
|
X173479047Y-53632380D01*
|
||||||
|
X173574285Y-53680000D01*
|
||||||
|
X173621904Y-53727619D01*
|
||||||
|
X173669523Y-53822857D01*
|
||||||
|
X173669523Y-53918095D01*
|
||||||
|
X173621904Y-54060952D01*
|
||||||
|
X173050476Y-54632380D01*
|
||||||
|
X173669523Y-54632380D01*
|
||||||
|
X174288571Y-53632380D02*
|
||||||
|
X174383809Y-53632380D01*
|
||||||
|
X174479047Y-53680000D01*
|
||||||
|
X174526666Y-53727619D01*
|
||||||
|
X174574285Y-53822857D01*
|
||||||
|
X174621904Y-54013333D01*
|
||||||
|
X174621904Y-54251428D01*
|
||||||
|
X174574285Y-54441904D01*
|
||||||
|
X174526666Y-54537142D01*
|
||||||
|
X174479047Y-54584761D01*
|
||||||
|
X174383809Y-54632380D01*
|
||||||
|
X174288571Y-54632380D01*
|
||||||
|
X174193333Y-54584761D01*
|
||||||
|
X174145714Y-54537142D01*
|
||||||
|
X174098095Y-54441904D01*
|
||||||
|
X174050476Y-54251428D01*
|
||||||
|
X174050476Y-54013333D01*
|
||||||
|
X174098095Y-53822857D01*
|
||||||
|
X174145714Y-53727619D01*
|
||||||
|
X174193333Y-53680000D01*
|
||||||
|
X174288571Y-53632380D01*
|
||||||
|
X175574285Y-54632380D02*
|
||||||
|
X175002857Y-54632380D01*
|
||||||
|
X175288571Y-54632380D02*
|
||||||
|
X175288571Y-53632380D01*
|
||||||
|
X175193333Y-53775238D01*
|
||||||
|
X175098095Y-53870476D01*
|
||||||
|
X175002857Y-53918095D01*
|
||||||
|
X176050476Y-54632380D02*
|
||||||
|
X176240952Y-54632380D01*
|
||||||
|
X176336190Y-54584761D01*
|
||||||
|
X176383809Y-54537142D01*
|
||||||
|
X176479047Y-54394285D01*
|
||||||
|
X176526666Y-54203809D01*
|
||||||
|
X176526666Y-53822857D01*
|
||||||
|
X176479047Y-53727619D01*
|
||||||
|
X176431428Y-53680000D01*
|
||||||
|
X176336190Y-53632380D01*
|
||||||
|
X176145714Y-53632380D01*
|
||||||
|
X176050476Y-53680000D01*
|
||||||
|
X176002857Y-53727619D01*
|
||||||
|
X175955238Y-53822857D01*
|
||||||
|
X175955238Y-54060952D01*
|
||||||
|
X176002857Y-54156190D01*
|
||||||
|
X176050476Y-54203809D01*
|
||||||
|
X176145714Y-54251428D01*
|
||||||
|
X176336190Y-54251428D01*
|
||||||
|
X176431428Y-54203809D01*
|
||||||
|
X176479047Y-54156190D01*
|
||||||
|
X176526666Y-54060952D01*
|
||||||
|
D11*
|
||||||
|
G04 #@! TO.C,U2*
|
||||||
|
X135890000Y-63540000D02*
|
||||||
|
X85090000Y-63540000D01*
|
||||||
|
X135890000Y-86400000D02*
|
||||||
|
X135890000Y-63540000D01*
|
||||||
|
X85090000Y-86400000D02*
|
||||||
|
X135890000Y-86400000D01*
|
||||||
|
X85090000Y-63540000D02*
|
||||||
|
X85090000Y-86400000D01*
|
||||||
|
D12*
|
||||||
|
G04 #@! TO.C,HX711-2*
|
||||||
|
X160020000Y-90375000D02*
|
||||||
|
X137160000Y-90375000D01*
|
||||||
|
X137160000Y-90375000D02*
|
||||||
|
X137160000Y-59895000D01*
|
||||||
|
X137160000Y-59895000D02*
|
||||||
|
X160020000Y-59895000D01*
|
||||||
|
X160020000Y-59895000D02*
|
||||||
|
X160020000Y-90375000D01*
|
||||||
|
D13*
|
||||||
|
X143406000Y-91391000D02*
|
||||||
|
G75*
|
||||||
|
G03X143406000Y-91391000I-150000J0D01*
|
||||||
|
G01*
|
||||||
|
D12*
|
||||||
|
G04 #@! TO.C,HX711-1*
|
||||||
|
X184150000Y-90375000D02*
|
||||||
|
X161290000Y-90375000D01*
|
||||||
|
X161290000Y-90375000D02*
|
||||||
|
X161290000Y-59895000D01*
|
||||||
|
X161290000Y-59895000D02*
|
||||||
|
X184150000Y-59895000D01*
|
||||||
|
X184150000Y-59895000D02*
|
||||||
|
X184150000Y-90375000D01*
|
||||||
|
D13*
|
||||||
|
X167536000Y-91391000D02*
|
||||||
|
G75*
|
||||||
|
G03X167536000Y-91391000I-150000J0D01*
|
||||||
|
G01*
|
||||||
|
D12*
|
||||||
|
G04 #@! TO.C,J1*
|
||||||
|
X193965000Y-79730000D02*
|
||||||
|
X193965000Y-92830000D01*
|
||||||
|
X193965000Y-92830000D02*
|
||||||
|
X193725000Y-92830000D01*
|
||||||
|
X186165000Y-92830000D02*
|
||||||
|
X189605000Y-92830000D01*
|
||||||
|
X186165000Y-79730000D02*
|
||||||
|
X189495000Y-79730000D01*
|
||||||
|
X193965000Y-79730000D02*
|
||||||
|
X193725000Y-79730000D01*
|
||||||
|
D14*
|
||||||
|
X185575000Y-85370000D02*
|
||||||
|
G75*
|
||||||
|
G03X185575000Y-85370000I-200000J0D01*
|
||||||
|
G01*
|
||||||
|
G04 #@! TO.C,J2*
|
||||||
|
X83630000Y-87190000D02*
|
||||||
|
G75*
|
||||||
|
G03X83630000Y-87190000I-200000J0D01*
|
||||||
|
G01*
|
||||||
|
D12*
|
||||||
|
X74840000Y-92830000D02*
|
||||||
|
X75080000Y-92830000D01*
|
||||||
|
X82640000Y-92830000D02*
|
||||||
|
X79310000Y-92830000D01*
|
||||||
|
X82640000Y-79730000D02*
|
||||||
|
X79200000Y-79730000D01*
|
||||||
|
X74840000Y-79730000D02*
|
||||||
|
X75080000Y-79730000D01*
|
||||||
|
X74840000Y-92830000D02*
|
||||||
|
X74840000Y-79730000D01*
|
||||||
|
G04 #@! TO.C,J3*
|
||||||
|
X80540000Y-56935000D02*
|
||||||
|
X80540000Y-60935000D01*
|
||||||
|
X80540000Y-63535000D02*
|
||||||
|
X80540000Y-69335000D01*
|
||||||
|
X80540000Y-72035000D02*
|
||||||
|
X80540000Y-75935000D01*
|
||||||
|
X80540000Y-75935000D02*
|
||||||
|
X74960000Y-75935000D01*
|
||||||
|
X74960000Y-56935000D02*
|
||||||
|
X80540000Y-56935000D01*
|
||||||
|
D10*
|
||||||
|
X81138000Y-65025000D02*
|
||||||
|
G75*
|
||||||
|
G03X81138000Y-65025000I-100000J0D01*
|
||||||
|
G01*
|
||||||
|
D12*
|
||||||
|
X74960000Y-56935000D02*
|
||||||
|
X74960000Y-75935000D01*
|
||||||
|
D15*
|
||||||
|
G04 #@! TO.C,J4*
|
||||||
|
X108605000Y-61085000D02*
|
||||||
|
X108605000Y-55115000D01*
|
||||||
|
X108605000Y-55115000D02*
|
||||||
|
X100985000Y-55115000D01*
|
||||||
|
X100985000Y-55115000D02*
|
||||||
|
X100985000Y-61085000D01*
|
||||||
|
X100985000Y-61085000D02*
|
||||||
|
X108605000Y-61085000D01*
|
||||||
|
X105295000Y-61075000D02*
|
||||||
|
X105295000Y-60325000D01*
|
||||||
|
X105295000Y-60325000D02*
|
||||||
|
X104295000Y-60325000D01*
|
||||||
|
X104295000Y-60325000D02*
|
||||||
|
X104295000Y-61075000D01*
|
||||||
|
X104295000Y-61075000D02*
|
||||||
|
X105295000Y-61075000D01*
|
||||||
|
X108595000Y-61075000D02*
|
||||||
|
X108595000Y-60325000D01*
|
||||||
|
X108595000Y-60325000D02*
|
||||||
|
X106795000Y-60325000D01*
|
||||||
|
X106795000Y-60325000D02*
|
||||||
|
X106795000Y-61075000D01*
|
||||||
|
X106795000Y-61075000D02*
|
||||||
|
X108595000Y-61075000D01*
|
||||||
|
X102795000Y-61075000D02*
|
||||||
|
X102795000Y-60325000D01*
|
||||||
|
X102795000Y-60325000D02*
|
||||||
|
X100995000Y-60325000D01*
|
||||||
|
X100995000Y-60325000D02*
|
||||||
|
X100995000Y-61075000D01*
|
||||||
|
X100995000Y-61075000D02*
|
||||||
|
X102795000Y-61075000D01*
|
||||||
|
X108595000Y-58825000D02*
|
||||||
|
X107845000Y-58825000D01*
|
||||||
|
X107845000Y-58825000D02*
|
||||||
|
X107845000Y-57485000D01*
|
||||||
|
X104795000Y-55875000D02*
|
||||||
|
X106785000Y-55875000D01*
|
||||||
|
X100995000Y-58825000D02*
|
||||||
|
X101745000Y-58825000D01*
|
||||||
|
X101745000Y-58825000D02*
|
||||||
|
X101745000Y-55875000D01*
|
||||||
|
X101745000Y-55875000D02*
|
||||||
|
X104795000Y-55875000D01*
|
||||||
|
X107645000Y-61375000D02*
|
||||||
|
X108895000Y-61375000D01*
|
||||||
|
X108895000Y-61375000D02*
|
||||||
|
X108895000Y-60125000D01*
|
||||||
|
G04 #@! TO.C,SW1*
|
||||||
|
X185545000Y-71465000D02*
|
||||||
|
X185545000Y-70165000D01*
|
||||||
|
X186845000Y-71465000D02*
|
||||||
|
X185545000Y-71465000D01*
|
||||||
|
X193195000Y-59215000D02*
|
||||||
|
X193195000Y-69115000D01*
|
||||||
|
X186495000Y-69115000D02*
|
||||||
|
X186495000Y-59215000D01*
|
||||||
|
X192445000Y-71165000D02*
|
||||||
|
X187245000Y-71165000D01*
|
||||||
|
X187245000Y-57165000D02*
|
||||||
|
X192445000Y-57165000D01*
|
||||||
|
G04 #@! TO.C,HX711-2*
|
||||||
|
D14*
|
||||||
|
X152924088Y-92607908D02*
|
||||||
|
X152924088Y-91607848D01*
|
||||||
|
X152924088Y-92084067D02*
|
||||||
|
X153495551Y-92084067D01*
|
||||||
|
X153495551Y-92607908D02*
|
||||||
|
X153495551Y-91607848D01*
|
||||||
|
X153876526Y-91607848D02*
|
||||||
|
X154543233Y-92607908D01*
|
||||||
|
X154543233Y-91607848D02*
|
||||||
|
X153876526Y-92607908D01*
|
||||||
|
X154828964Y-91607848D02*
|
||||||
|
X155495671Y-91607848D01*
|
||||||
|
X155067074Y-92607908D01*
|
||||||
|
X156400487Y-92607908D02*
|
||||||
|
X155829024Y-92607908D01*
|
||||||
|
X156114756Y-92607908D02*
|
||||||
|
X156114756Y-91607848D01*
|
||||||
|
X156019512Y-91750713D01*
|
||||||
|
X155924268Y-91845957D01*
|
||||||
|
X155829024Y-91893579D01*
|
||||||
|
X157352925Y-92607908D02*
|
||||||
|
X156781462Y-92607908D01*
|
||||||
|
X157067194Y-92607908D02*
|
||||||
|
X157067194Y-91607848D01*
|
||||||
|
X156971950Y-91750713D01*
|
||||||
|
X156876706Y-91845957D01*
|
||||||
|
X156781462Y-91893579D01*
|
||||||
|
X157781522Y-92226932D02*
|
||||||
|
X158543473Y-92226932D01*
|
||||||
|
X158972070Y-91703091D02*
|
||||||
|
X159019692Y-91655470D01*
|
||||||
|
X159114936Y-91607848D01*
|
||||||
|
X159353045Y-91607848D01*
|
||||||
|
X159448289Y-91655470D01*
|
||||||
|
X159495911Y-91703091D01*
|
||||||
|
X159543533Y-91798335D01*
|
||||||
|
X159543533Y-91893579D01*
|
||||||
|
X159495911Y-92036445D01*
|
||||||
|
X158924448Y-92607908D01*
|
||||||
|
X159543533Y-92607908D01*
|
||||||
|
G04 #@! TO.C,HX711-1*
|
||||||
|
X161814088Y-92607908D02*
|
||||||
|
X161814088Y-91607848D01*
|
||||||
|
X161814088Y-92084067D02*
|
||||||
|
X162385551Y-92084067D01*
|
||||||
|
X162385551Y-92607908D02*
|
||||||
|
X162385551Y-91607848D01*
|
||||||
|
X162766526Y-91607848D02*
|
||||||
|
X163433233Y-92607908D01*
|
||||||
|
X163433233Y-91607848D02*
|
||||||
|
X162766526Y-92607908D01*
|
||||||
|
X163718964Y-91607848D02*
|
||||||
|
X164385671Y-91607848D01*
|
||||||
|
X163957074Y-92607908D01*
|
||||||
|
X165290487Y-92607908D02*
|
||||||
|
X164719024Y-92607908D01*
|
||||||
|
X165004756Y-92607908D02*
|
||||||
|
X165004756Y-91607848D01*
|
||||||
|
X164909512Y-91750713D01*
|
||||||
|
X164814268Y-91845957D01*
|
||||||
|
X164719024Y-91893579D01*
|
||||||
|
X166242925Y-92607908D02*
|
||||||
|
X165671462Y-92607908D01*
|
||||||
|
X165957194Y-92607908D02*
|
||||||
|
X165957194Y-91607848D01*
|
||||||
|
X165861950Y-91750713D01*
|
||||||
|
X165766706Y-91845957D01*
|
||||||
|
X165671462Y-91893579D01*
|
||||||
|
X166671522Y-92226932D02*
|
||||||
|
X167433473Y-92226932D01*
|
||||||
|
X168433533Y-92607908D02*
|
||||||
|
X167862070Y-92607908D01*
|
||||||
|
X168147801Y-92607908D02*
|
||||||
|
X168147801Y-91607848D01*
|
||||||
|
X168052558Y-91750713D01*
|
||||||
|
X167957314Y-91845957D01*
|
||||||
|
X167862070Y-91893579D01*
|
||||||
|
G04 #@! TO.C,J1*
|
||||||
|
X186556296Y-93986773D02*
|
||||||
|
X186556296Y-94701851D01*
|
||||||
|
X186508624Y-94844867D01*
|
||||||
|
X186413280Y-94940211D01*
|
||||||
|
X186270265Y-94987883D01*
|
||||||
|
X186174921Y-94987883D01*
|
||||||
|
X187557406Y-94987883D02*
|
||||||
|
X186985343Y-94987883D01*
|
||||||
|
X187271375Y-94987883D02*
|
||||||
|
X187271375Y-93986773D01*
|
||||||
|
X187176031Y-94129788D01*
|
||||||
|
X187080687Y-94225132D01*
|
||||||
|
X186985343Y-94272804D01*
|
||||||
|
G04 #@! TO.C,J2*
|
||||||
|
X81581296Y-93986773D02*
|
||||||
|
X81581296Y-94701851D01*
|
||||||
|
X81533624Y-94844867D01*
|
||||||
|
X81438280Y-94940211D01*
|
||||||
|
X81295265Y-94987883D01*
|
||||||
|
X81199921Y-94987883D01*
|
||||||
|
X82010343Y-94082116D02*
|
||||||
|
X82058015Y-94034445D01*
|
||||||
|
X82153359Y-93986773D01*
|
||||||
|
X82391719Y-93986773D01*
|
||||||
|
X82487062Y-94034445D01*
|
||||||
|
X82534734Y-94082116D01*
|
||||||
|
X82582406Y-94177460D01*
|
||||||
|
X82582406Y-94272804D01*
|
||||||
|
X82534734Y-94415820D01*
|
||||||
|
X81962671Y-94987883D01*
|
||||||
|
X82582406Y-94987883D01*
|
||||||
|
G04 #@! TO.C,J3*
|
||||||
|
X79675383Y-54900272D02*
|
||||||
|
X79675383Y-55617308D01*
|
||||||
|
X79627580Y-55760715D01*
|
||||||
|
X79531976Y-55856320D01*
|
||||||
|
X79388569Y-55904122D01*
|
||||||
|
X79292964Y-55904122D01*
|
||||||
|
X80057802Y-54900272D02*
|
||||||
|
X80679233Y-54900272D01*
|
||||||
|
X80344616Y-55282691D01*
|
||||||
|
X80488023Y-55282691D01*
|
||||||
|
X80583628Y-55330494D01*
|
||||||
|
X80631430Y-55378296D01*
|
||||||
|
X80679233Y-55473901D01*
|
||||||
|
X80679233Y-55712913D01*
|
||||||
|
X80631430Y-55808517D01*
|
||||||
|
X80583628Y-55856320D01*
|
||||||
|
X80488023Y-55904122D01*
|
||||||
|
X80201209Y-55904122D01*
|
||||||
|
X80105604Y-55856320D01*
|
||||||
|
X80057802Y-55808517D01*
|
||||||
|
G04 #@! TO.C,J4*
|
||||||
|
X98726666Y-59982380D02*
|
||||||
|
X98726666Y-60696666D01*
|
||||||
|
X98679047Y-60839523D01*
|
||||||
|
X98583809Y-60934761D01*
|
||||||
|
X98440952Y-60982380D01*
|
||||||
|
X98345714Y-60982380D01*
|
||||||
|
X99631428Y-60315714D02*
|
||||||
|
X99631428Y-60982380D01*
|
||||||
|
X99393333Y-59934761D02*
|
||||||
|
X99155238Y-60649047D01*
|
||||||
|
X99774285Y-60649047D01*
|
||||||
|
G04 #@! TO.C,SW1*
|
||||||
|
X185991666Y-56074761D02*
|
||||||
|
X186134523Y-56122380D01*
|
||||||
|
X186372619Y-56122380D01*
|
||||||
|
X186467857Y-56074761D01*
|
||||||
|
X186515476Y-56027142D01*
|
||||||
|
X186563095Y-55931904D01*
|
||||||
|
X186563095Y-55836666D01*
|
||||||
|
X186515476Y-55741428D01*
|
||||||
|
X186467857Y-55693809D01*
|
||||||
|
X186372619Y-55646190D01*
|
||||||
|
X186182142Y-55598571D01*
|
||||||
|
X186086904Y-55550952D01*
|
||||||
|
X186039285Y-55503333D01*
|
||||||
|
X185991666Y-55408095D01*
|
||||||
|
X185991666Y-55312857D01*
|
||||||
|
X186039285Y-55217619D01*
|
||||||
|
X186086904Y-55170000D01*
|
||||||
|
X186182142Y-55122380D01*
|
||||||
|
X186420238Y-55122380D01*
|
||||||
|
X186563095Y-55170000D01*
|
||||||
|
X186896428Y-55122380D02*
|
||||||
|
X187134523Y-56122380D01*
|
||||||
|
X187325000Y-55408095D01*
|
||||||
|
X187515476Y-56122380D01*
|
||||||
|
X187753571Y-55122380D01*
|
||||||
|
X188658333Y-56122380D02*
|
||||||
|
X188086904Y-56122380D01*
|
||||||
|
X188372619Y-56122380D02*
|
||||||
|
X188372619Y-55122380D01*
|
||||||
|
X188277380Y-55265238D01*
|
||||||
|
X188182142Y-55360476D01*
|
||||||
|
X188086904Y-55408095D01*
|
||||||
|
G04 #@! TD*
|
||||||
|
M02*
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
M48
|
||||||
|
;DRILL file {KiCad 5.0.2-5.fc29} date Fr 22 Mär 2019 17:51:56 CET
|
||||||
|
;FORMAT={-:-/ absolute / inch / decimal}
|
||||||
|
FMAT,2
|
||||||
|
INCH,TZ
|
||||||
|
T1C0.0157
|
||||||
|
T2C0.0276
|
||||||
|
T3C0.0354
|
||||||
|
T4C0.0390
|
||||||
|
T5C0.0394
|
||||||
|
T6C0.0400
|
||||||
|
T7C0.0472
|
||||||
|
T8C0.0866
|
||||||
|
T9C0.1000
|
||||||
|
T10C0.0472
|
||||||
|
%
|
||||||
|
G90
|
||||||
|
G05
|
||||||
|
T1
|
||||||
|
X4.425Y-3.1831
|
||||||
|
T2
|
||||||
|
X3.0685Y-2.59
|
||||||
|
X3.0685Y-2.6411
|
||||||
|
X3.1315Y-2.5644
|
||||||
|
X3.1315Y-2.6156
|
||||||
|
X3.1315Y-2.6667
|
||||||
|
T3
|
||||||
|
X7.425Y-2.3687
|
||||||
|
X7.425Y-2.5262
|
||||||
|
X7.425Y-2.6837
|
||||||
|
X3.2299Y-3.2197
|
||||||
|
X3.2299Y-3.2906
|
||||||
|
X3.2299Y-3.3614
|
||||||
|
X3.2299Y-3.4323
|
||||||
|
X3.2299Y-3.5031
|
||||||
|
X3.2299Y-3.574
|
||||||
|
X7.353Y-3.2197
|
||||||
|
X7.353Y-3.2906
|
||||||
|
X7.353Y-3.3614
|
||||||
|
X7.353Y-3.4323
|
||||||
|
X7.353Y-3.5031
|
||||||
|
X7.353Y-3.574
|
||||||
|
T4
|
||||||
|
X3.6Y-3.3516
|
||||||
|
X3.7Y-3.3516
|
||||||
|
X3.8Y-3.3516
|
||||||
|
X3.9Y-3.3516
|
||||||
|
X4.Y-2.5516
|
||||||
|
X4.Y-3.3516
|
||||||
|
X4.1Y-2.5516
|
||||||
|
X4.1Y-3.3516
|
||||||
|
X4.2Y-2.5516
|
||||||
|
X4.2Y-3.3516
|
||||||
|
X4.3Y-2.5516
|
||||||
|
X4.3Y-3.3516
|
||||||
|
X4.4Y-2.5516
|
||||||
|
X4.4Y-3.3516
|
||||||
|
X4.5Y-2.5516
|
||||||
|
X4.5Y-3.3516
|
||||||
|
X4.6Y-2.5516
|
||||||
|
X4.6Y-3.3516
|
||||||
|
X4.7Y-2.5516
|
||||||
|
X4.7Y-3.3516
|
||||||
|
X4.8Y-2.5516
|
||||||
|
X4.8Y-3.3516
|
||||||
|
X4.9Y-2.5516
|
||||||
|
X4.9Y-3.3516
|
||||||
|
X5.Y-2.5516
|
||||||
|
X5.Y-3.3516
|
||||||
|
X5.1Y-2.5516
|
||||||
|
X5.1Y-3.3516
|
||||||
|
T5
|
||||||
|
X3.037Y-3.1449
|
||||||
|
X3.037Y-3.6488
|
||||||
|
X3.1Y-2.4482
|
||||||
|
X3.1Y-2.7829
|
||||||
|
X7.5459Y-3.1449
|
||||||
|
X7.5459Y-3.6488
|
||||||
|
X4.0766Y-2.3081
|
||||||
|
X4.175Y-2.3081
|
||||||
|
T6
|
||||||
|
X6.6Y-2.4081
|
||||||
|
X6.6Y-3.5081
|
||||||
|
X6.7Y-2.4081
|
||||||
|
X6.7Y-3.5081
|
||||||
|
X6.8Y-2.4081
|
||||||
|
X6.8Y-3.5081
|
||||||
|
X6.9Y-2.4081
|
||||||
|
X6.9Y-2.7081
|
||||||
|
X6.9Y-3.5081
|
||||||
|
X7.Y-2.4081
|
||||||
|
X7.Y-2.7081
|
||||||
|
X7.Y-3.5081
|
||||||
|
X5.65Y-2.4081
|
||||||
|
X5.65Y-3.5081
|
||||||
|
X5.75Y-2.4081
|
||||||
|
X5.75Y-3.5081
|
||||||
|
X5.85Y-2.4081
|
||||||
|
X5.85Y-3.5081
|
||||||
|
X5.95Y-2.4081
|
||||||
|
X5.95Y-2.7081
|
||||||
|
X5.95Y-3.5081
|
||||||
|
X6.05Y-2.4081
|
||||||
|
X6.05Y-2.7081
|
||||||
|
X6.05Y-3.5081
|
||||||
|
T7
|
||||||
|
X7.3561Y-2.29
|
||||||
|
X7.3561Y-2.7624
|
||||||
|
X7.5923Y-2.29
|
||||||
|
X7.5923Y-2.7624
|
||||||
|
T8
|
||||||
|
X3.0646Y-3.3969
|
||||||
|
X7.5183Y-3.3969
|
||||||
|
T9
|
||||||
|
X3.45Y-2.6016
|
||||||
|
X3.45Y-3.3016
|
||||||
|
X5.25Y-2.6016
|
||||||
|
X5.25Y-3.3016
|
||||||
|
T10
|
||||||
|
X4.238Y-2.2293
|
||||||
|
T0
|
||||||
|
M30
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
(sym_lib_table
|
||||||
|
(lib (name beieliscale-kicad-eagle-import)(type Legacy)(uri ${KIPRJMOD}/beieliscale-kicad-eagle-import.lib)(options "")(descr ""))
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
from time import sleep
|
||||||
|
import serial
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
while (True):
|
||||||
|
serial_not_open = True
|
||||||
|
while serial_not_open:
|
||||||
|
try:
|
||||||
|
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
|
||||||
|
except:
|
||||||
|
sleep(0.5)
|
||||||
|
else:
|
||||||
|
serial_not_open = False
|
||||||
|
|
||||||
|
no_exception = True
|
||||||
|
while no_exception:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
while ser.inWaiting():
|
||||||
|
print(ser.read().decode('utf-8'), end='')
|
||||||
|
sleep(0.1)
|
||||||
|
except:
|
||||||
|
print(datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")," - Serial Device disappeared...")
|
||||||
|
ser.close()
|
||||||
|
no_exception = False
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
from time import sleep
|
||||||
|
import serial
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
while (True):
|
||||||
|
serial_not_open = True
|
||||||
|
while serial_not_open:
|
||||||
|
try:
|
||||||
|
ser = serial.Serial('/dev/ttyUSB1', 115200, timeout=1)
|
||||||
|
except:
|
||||||
|
sleep(0.5)
|
||||||
|
else:
|
||||||
|
serial_not_open = False
|
||||||
|
|
||||||
|
no_exception = True
|
||||||
|
while no_exception:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
while ser.inWaiting():
|
||||||
|
print(ser.read().decode('utf-8'), end='')
|
||||||
|
sleep(0.1)
|
||||||
|
except:
|
||||||
|
print(datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")," - Serial Device disappeared...")
|
||||||
|
ser.close()
|
||||||
|
no_exception = False
|
||||||