diff --git a/lib/LICENSE b/lib/LICENSE new file mode 100755 index 0000000..f03571c --- /dev/null +++ b/lib/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2021 Luis Rodil-Fernandez + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/README.md b/lib/README.md new file mode 100755 index 0000000..c4e2e16 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,6 @@ +# DERFUNKE McUKIT + +This is a collection of libraries for common needs when programming Arduino's or ESP microcontrollers. Meant for own use and for use in teaching. + +Run `git submodule init` on this directory to fetch the libraries that are not part of the unirepo. + diff --git a/lib/corestats/LICENSE b/lib/corestats/LICENSE new file mode 100755 index 0000000..98321a3 --- /dev/null +++ b/lib/corestats/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Luis Rodil-Fernandez + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/corestats/README.md b/lib/corestats/README.md new file mode 100755 index 0000000..194ede8 --- /dev/null +++ b/lib/corestats/README.md @@ -0,0 +1,6 @@ +## Core Analog Statistics + +A support library for analog time series analysis. + +Code mostly borrowed from [Plaquette by Sofian Audrey](https://github.com/SofaPirate/Plaquette). + diff --git a/lib/corestats/corestats.cpp b/lib/corestats/corestats.cpp new file mode 100755 index 0000000..28bcee0 --- /dev/null +++ b/lib/corestats/corestats.cpp @@ -0,0 +1,188 @@ +#include + +#include +#include +#include +#include + +// ////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////// + +float Stats::stddev() const { + return sqrt(var()); +} + +float Stats::normalize(float value) const { + return ( value - mean() ) / (stddev() + FLT_MIN); +} + + +SimpleStats::SimpleStats(float startMean, float startVar) { + reset(startMean, startVar); +} + +void SimpleStats::reset(float startMean, float startVar) { + _mean = startMean; + _mean2 = startVar + sq(_mean); + _nSamples = 0; +// _min = FLT_MAX; +// _max = -FLT_MAX; +} + +float SimpleStats::update(float value) { + if (_nSamples == ULONG_MAX) + _nSamples = (ULONG_MAX / 4) * 3; // simple trick that makes sure we don't overflow + + // Add one to number of samples + _nSamples++; + + // Update mean and mean2 + float prop = (float)(_nSamples-1) / (float)_nSamples; + _mean = _mean * prop + value / _nSamples; + _mean2 = _mean2 * prop + sq(value) / _nSamples; + + // Update min and max +// _min = min(_min, value); +// _max = max(_max, value); + + return normalize(value); +} + +float SimpleStats::var() const { + float v = (_mean2 - sq(_mean)); + return max(v, (float)0); // make sure the result is >= 0 +} + +// ////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////// + +MovingAverage::MovingAverage(float alphaOrN) : _value(0.5f) { + setAlphaOrN(alphaOrN); + reset(); +} + +MovingAverage::MovingAverage(float alphaOrN, float startValue) : _value(startValue) { + setAlphaOrN(alphaOrN); +} + +void MovingAverage::setAlphaOrN(float alphaOrN) +{ + alphaOrN = max(alphaOrN, 0); // make sure factor >= 0 + _alpha = (alphaOrN > 1 ? + 2 / (alphaOrN + 1) : + alphaOrN); +} + +void MovingAverage::reset() { + _setStarted(false); +} + +void MovingAverage::reset(float startValue) { + _value = startValue; + _setStarted(true); +} + +float MovingAverage::update(float v) { + if (!isStarted()) { + _value = v; + _setStarted(true); // start + return _value; + } + else + return (_value -= _alpha * (_value - v)); +} + +bool MovingAverage::isStarted() const { + return _alpha >= 0; +} + +void MovingAverage::_setStarted(bool start) { + _alpha = (start ? +1 : -1) * abs(_alpha); +} + +MovingStats::MovingStats(float alphaOrN) : avg(alphaOrN) { } +MovingStats::MovingStats(float alphaOrN, float startMean, float startVar) + : avg(alphaOrN, startMean), _var(startVar) { + reset(startMean, startVar); +} + +void MovingStats::reset() { + avg.reset(); + _var = 0; +} + +void MovingStats::reset(float startMean, float startVar) { + avg.reset(startMean); + _var = startVar; +} + +float MovingStats::update(float value) + { + avg.update(value); + if (!isStarted()) + _var = 0; + else { + float diff = value - avg.get(); + _var -= avg.alpha() * (_var - sq(diff)); + } + + return normalize(value); +} + +bool MovingStats::isStarted() const { + return avg.isStarted(); +} + +// ////////////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////////////// + +AdaptiveNormalizer::AdaptiveNormalizer(float smoothFactor) + : MovingStats(smoothFactor), + _value(0.5f), + _mean(0.5f), + _stddev(0.25f) +{} + +AdaptiveNormalizer::AdaptiveNormalizer(float mean, float stddev, float smoothFactor) + : MovingStats(smoothFactor), + _value(mean), + _mean(mean), + _stddev(abs(stddev)) +{} + +float AdaptiveNormalizer::put(float value) { + return (_value = MovingStats::update(value) * _stddev + _mean); +} + +Normalizer::Normalizer() + : SimpleStats(), + _value(0.5f), + _mean(0.5f), + _stddev(0.25f) +{} + +Normalizer::Normalizer(float mean, float stddev) + : SimpleStats(), + _value(mean), + _mean(mean), + _stddev(abs(stddev)) +{} + +float Normalizer::put(float value) { + return (_value = SimpleStats::update(value) * _stddev + _mean); +} + +MinMaxScaler::MinMaxScaler() + : _value(0.5f), + _minValue(FLT_MAX), + _maxValue(FLT_MIN) +{} + +float MinMaxScaler::put(float value) +{ + _minValue = min(value, _minValue); + _maxValue = max(value, _maxValue); + _value = (_minValue == _maxValue ? 0.5f : map(value, _minValue, _maxValue, 0.0f, 1.0f)); + return _value; +} + diff --git a/lib/corestats/corestats.h b/lib/corestats/corestats.h new file mode 100755 index 0000000..436def4 --- /dev/null +++ b/lib/corestats/corestats.h @@ -0,0 +1,180 @@ +#ifndef __CORESTATS_H__ +#define __CORESTATS_H__ + +class Stats { +public: + virtual ~Stats() {} + + /// Resets the statistics. + virtual void reset(float startMean=0, float startVar=0) = 0; + + /// Adds a value to the statistics (returns the mean). + virtual float update(float value) = 0; + + /// The statistics. + virtual float mean() const = 0; + virtual float var() const = 0; + virtual float stddev() const; + + /// Returns the normalized value according to the computed statistics (mean and variance). + float normalize(float value) const; +}; + +class SimpleStats : public Stats { +public: + float _mean; + float _mean2; // mean of squared values + + unsigned long _nSamples; + + /// ctor + SimpleStats(float startMean=0, float startVar=0); + virtual ~SimpleStats() {} + + /// Resets the statistics. + virtual void reset(float startMean=0, float startVar=0); + + /// Adds a value to the statistics (returns the mean). + virtual float update(float value); + + /// The statistics. + virtual float mean() const { return _mean; } + // The var() and stddev() are the population (ie. not the sample) variance and standard dev, so technically + // they should be readjusted by multiplying it by _nSamples / (_nSamples-1). But with a lot of samples the + // difference vanishes and we priviledged less floating points computations over precision. + virtual float var() const; +}; + +/// An exponential moving average class. +class MovingAverage { +public: + // The alpha (mixing) variable (in [0,1]). + float _alpha; + + // The current value of the exponential moving average. + float _value; + + /** + * Constructs the moving average, starting with #startValue# as its value. The #alphaOrN# argument + * has two options: + * - if <= 1 then it's used directly as the alpha value + * - if > 1 then it's used as the "number of items that are considered from the past" (*) + * (*) Of course this is an approximation. It actually sets the alpha value to 2 / (n - 1) + */ + MovingAverage(float alphaOrN=1); + MovingAverage(float alphaOrN, float startValue); + virtual ~MovingAverage() {} + + /// Change the smoothing factor to #alphaOrN#. + void setAlphaOrN(float alphaOrN); + + /// Resets the moving average. + void reset(); + + /// Resets the moving average to #startValue#. + void reset(float startValue); + + /// Updates the moving average with new value #v# (also returns the current value). + float update(float v); + + /// Returns the value of the moving average. This is undefined if isValid() == false. + float get() const { return _value; } + + /// Returns true iff the moving average has already been started. + bool isStarted() const; + + /// Returns the alpha value. + float alpha() const { return _alpha; } + +protected: + void _setStarted(bool start); +}; + +class MovingStats : public Stats { +public: + MovingAverage avg; + float _var; + + /** + * Constructs the moving statistics, starting with #startMean# and #startVar# as initial mean and + * variance. The #alphaOrN# argument has two options: + * - if <= 1 then it's used directly as the alpha value + * - if > 1 then it's used as the "number of items that are considered from the past" (*) + * (*) Of course this is an approximation. It actually sets the alpha value to 2 / (n - 1) + */ + MovingStats(float alphaOrN=1); + MovingStats(float alphaOrN, float startMean, float startVar); + virtual ~MovingStats() {} + + /// Resets the statistics. + virtual void reset(); + + /// Resets the statistics. + virtual void reset(float startMean, float startVar); + + /// Adds a value to the statistics (returns the mean). + virtual float update(float value); + + /// The statistics. + virtual float mean() const { return avg.get(); } + virtual float var() const { return _var; } + + virtual bool isStarted() const; +}; + + +/// Adaptive normalizer: normalizes values on-the-run using exponential moving +/// averages over mean and stddev. +class AdaptiveNormalizer : public MovingStats { +public: + AdaptiveNormalizer(float smoothFactor=0.001f); + AdaptiveNormalizer(float mean, float stddev, float smoothFactor=0.001f); + virtual ~AdaptiveNormalizer() {} + + void setMean(float mean) { _mean = mean; } + void setStddev(float stddev) { _stddev = stddev; }; + + virtual float put(float value); + + virtual float get() { return _value; } + + float _value; + float _mean; + float _stddev; +}; + +/// Standard normalizer: normalizes values on-the-run using real mean and stddev. +class Normalizer : public SimpleStats { +public: + Normalizer(); + Normalizer(float mean, float stddev); + virtual ~Normalizer() {} + + void setMean(float mean) { _mean = mean; } + void setStddev(float stddev) { _stddev = stddev; }; + + virtual float put(float value); + + virtual float get() { return _value; } + + float _value; + float _mean; + float _stddev; +}; + +/// Regularizes signal into [0,1] by rescaling it using the min and max values. +class MinMaxScaler { +public: + MinMaxScaler(); + virtual ~MinMaxScaler() {} + + virtual float put(float value); + + virtual float get() { return _value; } + + float _value; + float _minValue; + float _maxValue; +}; + +#endif // __CORESTATS_H__ \ No newline at end of file diff --git a/lib/corestats/examples/normalize/normalize.ino b/lib/corestats/examples/normalize/normalize.ino new file mode 100755 index 0000000..3bd8230 --- /dev/null +++ b/lib/corestats/examples/normalize/normalize.ino @@ -0,0 +1,24 @@ +#include + +#define SENSOR_PIN A0 + +// normalize incoming signal to be inside range [0, 1] +AdaptiveNormalizer normalizer(0, 1); + +void setup() { + Serial.begin(115200); +} + +void loop() { + // process input. + int reading = analogRead(SENSOR_PIN); + + normalizer.put( reading ); + + Serial.print(reading); + Serial.print(","); + Serial.print( normalizer.get() ); + Serial.println(); + + delay(20); +} diff --git a/lib/corestats/examples/runningavg/runningavg.ino b/lib/corestats/examples/runningavg/runningavg.ino new file mode 100755 index 0000000..0eb1e45 --- /dev/null +++ b/lib/corestats/examples/runningavg/runningavg.ino @@ -0,0 +1,23 @@ +#include + +#define SENSOR_PIN A0 + +MovingAverage mavg(0.01); + +void setup() { + Serial.begin(115200); +} + +void loop() { + // process input. + int reading = analogRead(SENSOR_PIN); + + mavg.update( reading ); + + Serial.print(reading); + Serial.print(","); + Serial.print( mavg.get() ); + Serial.println(); + + delay(20); +} diff --git a/lib/corestats/keywords.txt b/lib/corestats/keywords.txt new file mode 100755 index 0000000..1d551d8 --- /dev/null +++ b/lib/corestats/keywords.txt @@ -0,0 +1,39 @@ +####################################### +# Syntax Coloring Map For Test +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Stats KEYWORD1 +SimpleStats KEYWORD1 +MovingAverage KEYWORD1 +MovingStats KEYWORD1 +AdaptiveNormalizer KEYWORD1 +Normalizer KEYWORD1 +MinMaxScaler KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +put KEYWORD2 +get KEYWORD2 +mean KEYWORD2 +var KEYWORD2 +stddev KEYWORD2 +normalize KEYWORD2 +reset KEYWORD2 +update KEYWORD2 +alpha KEYWORD2 +isStarted KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/derfunke/README.md b/lib/derfunke/README.md new file mode 100755 index 0000000..d5924c4 --- /dev/null +++ b/lib/derfunke/README.md @@ -0,0 +1 @@ +## Vanity files diff --git a/lib/derfunke/example/header.cpp b/lib/derfunke/example/header.cpp new file mode 100755 index 0000000..033a837 --- /dev/null +++ b/lib/derfunke/example/header.cpp @@ -0,0 +1,15 @@ +#include + +void setup() +{ + Serial.begin(115200); + // welcome serial output header + df_header_print(); +} + + +void loop() +{ + delay(500); +} + diff --git a/lib/derfunke/src/derfunke.cpp b/lib/derfunke/src/derfunke.cpp new file mode 100755 index 0000000..4812e68 --- /dev/null +++ b/lib/derfunke/src/derfunke.cpp @@ -0,0 +1,12 @@ +#include +#include "derfunke.h" + +void df_header_print() { + Serial.println(" __ ___ __ "); + Serial.println(" ___/ /__ ____/ _/_ _____ / /_____ "); + Serial.println("/ _ / -_) __/ _/ // / _ \\/ '_/ -_)"); + Serial.println("\\_,_/\\__/_/ /_/ \\_,_/_//_/_/\\_\\__/ "); + Serial.print (" M C U K I T "); + Serial.println(MCUKIT_RELEASE); + Serial.println(); +} diff --git a/lib/derfunke/src/derfunke.h b/lib/derfunke/src/derfunke.h new file mode 100755 index 0000000..10cb76d --- /dev/null +++ b/lib/derfunke/src/derfunke.h @@ -0,0 +1,5 @@ +#pragma once + +#define MCUKIT_RELEASE "r12" + +void df_header_print(); diff --git a/lib/easywifi/README.md b/lib/easywifi/README.md new file mode 100755 index 0000000..6788296 --- /dev/null +++ b/lib/easywifi/README.md @@ -0,0 +1,4 @@ +# Easy Wifi + +Wraps around Wifi connectivity to make it easy for students to connect their devices to wifi + diff --git a/lib/easywifi/example/client.cpp b/lib/easywifi/example/client.cpp new file mode 100755 index 0000000..66733f1 --- /dev/null +++ b/lib/easywifi/example/client.cpp @@ -0,0 +1,24 @@ +#include +#include + +#define WIFI_SSID "somessid" +#define WIFI_PASSWORD "somepassword" + +void setup() { + Serial.begin( 9600 ); + while(!Serial); // wait until the serial connection is stablished + + // connect to existing access point as client + if( wifi_connect_as_client(WIFI_SSID, WIFI_PASSWORD) ) { + // print debugging information + wifi_print_mode(); + wifi_print_ip(); + } else { + Serial.print("Failed to connect to wifi "); + Serial.print( WIFI_SSID ); + Serial.println(); + } +} + +void loop() { +} diff --git a/lib/easywifi/src/easywifi.cpp b/lib/easywifi/src/easywifi.cpp new file mode 100755 index 0000000..45a4106 --- /dev/null +++ b/lib/easywifi/src/easywifi.cpp @@ -0,0 +1,146 @@ +#define LOG_ENABLED + +#if defined(ARDUINO_ARCH_ESP32) +#include +#else +#include +#endif + +#include +#include +#include "easywifi.h" +#include + +// IPAddress thisip; +// WifiMode mode; +// String apssid = "default_ap"; +// String _ssid = "unknown", _password = "unknown"; + +tWifiSettings wifi; + +// default network settings when operating as an AP +IPAddress ip_static = IPAddress(10, 0, 0, 1); +IPAddress gw_static = IPAddress(10, 0, 0, 1); +IPAddress sn_static = IPAddress(255, 255, 255, 0); + +void wifi_set_credentials(const char *ssid, const char *passw) { + wifi.ssid = ssid; + wifi.password = passw; +} + +void wifi_set_default_ap_name(const char *name) { + wifi.apssid = name; +} + +/** + * connect to WiFi access point as client station + * + * @param ssid to connect to + * @param passw password + * @param timeout is in seconds + */ +bool wifi_connect_as_client(const char *ssid, const char *passw, int timeouts) { + boolean succeeded = true; + + wifi_set_credentials(ssid, passw); + + WiFi.mode(WIFI_STA); // both hotspot and client are enabled + WiFi.begin(ssid, passw); + LOG("Connecting to WiFi "); + LOG(ssid); + LOG_NEW_LINE + + // wait for connection + LOG("Connecting"); + unsigned long tout = millis() + (timeouts * 1000); + while (WiFi.status() != WL_CONNECTED) { + delay(200); + Serial.print("."); + if (millis() > tout) { + succeeded = false; + break; + } + } + LOG_NEW_LINE + + // if we are connected we probably were assigned an IP + if (succeeded) { + wifi.thisip = WiFi.localIP(); + } + + wifi.mode = WifiMode::CLIENT; + + return succeeded; +} + +bool wifi_create_ap(const char *myssid) { + WiFi.mode(WIFI_AP); + + // optional soft ip config + LOG("Custom AP IP/GW/Subnet"); + LOG_NEW_LINE + WiFi.softAPConfig(ip_static, gw_static, sn_static); + + WiFi.softAP(myssid); + LOG("Creating WiFi access point with name "); + LOG(myssid); + LOG_NEW_LINE + + // let a long delay happen here, otherwise we might not get an IP + delay(1000); + + // // setup the DNS server redirecting all the domains to the ap IP + // dnsServer.setErrorReplyCode(DNSReplyCode::NoError); + // dnsServer.start(DNS_PORT, "*", WiFi.softAPIP()); + + wifi.thisip = WiFi.softAPIP(); + + wifi.apssid = myssid; + wifi.mode = WifiMode::ACCESS_POINT; + + return true; +} + +void wifi_print_ip() { + LOG("IP address: "); + LOG( wifi.thisip ); +} + +void wifi_print_mode() { + if( WifiMode::CLIENT == wifi.mode ) { + LOG("Connected to "); + LOG(wifi.ssid); + LOG(" as client"); + LOG_NEW_LINE + } else if (WifiMode::ACCESS_POINT == wifi.mode) { + LOG("Created "); + LOG(wifi.apssid); + LOG(" access point"); + LOG_NEW_LINE + } +} + +void wifi_init() +{ + // first try to connect to a given WiFi AP + if( wifi_connect_as_client( wifi.ssid.c_str(), wifi.password.c_str()) ) { + // // save IP + // persistence_save_settings(); + + // // create mDNS entry + // String mdns = "pyropanda" + thisip[3]; + // network_create_mdns_entry( mdns.c_str() ); + } else { + // if we do not succeed at connecting to an existing AP, create our own + // and setup DNS to channel all connections to the captive portal + LOG("Connection failed."); + LOG_NEW_LINE + + wifi_create_ap( wifi.apssid.c_str() ); + } + + // always print debug info + wifi_print_mode(); + wifi_print_ip(); + LOG_NEW_LINE +} // wifi_init diff --git a/lib/easywifi/src/easywifi.h b/lib/easywifi/src/easywifi.h new file mode 100755 index 0000000..457c44d --- /dev/null +++ b/lib/easywifi/src/easywifi.h @@ -0,0 +1,34 @@ +#ifndef __EASYWIFI_H__ +#define __EASYWIFI_H__ + +#include + +#ifndef __NANOLOG_H__ +#warning "the easywifi library needs the nanolog library as well" +#endif + +enum WifiMode { + CLIENT = 10, // station node + HYBRID_AP = 15, // station + ap + ACCESS_POINT = 20, // ap only + MESH = 30 // mesh +}; + +struct tWifiSettings { + IPAddress thisip; + WifiMode mode; + String apssid; + String ssid, password; +}; + +extern tWifiSettings wifi; + +void wifi_init(); +void wifi_set_credentials(const char *ssid, const char *passw); +void wifi_set_default_ap_name(const char *ssid); +void wifi_print_ip(); +void wifi_print_mode(); +bool wifi_connect_as_client(const char *ssid, const char *passw, int timeouts = 10); +bool wifi_create_ap(const char *myssid); + +#endif // __EASYWIFI_H__ \ No newline at end of file diff --git a/lib/nanolog/README.md b/lib/nanolog/README.md new file mode 100755 index 0000000..0ea6eed --- /dev/null +++ b/lib/nanolog/README.md @@ -0,0 +1,3 @@ +# Nanolog + +Simple serial logging library for microcontrollers diff --git a/lib/nanolog/src/nanolog.h b/lib/nanolog/src/nanolog.h new file mode 100755 index 0000000..a35b300 --- /dev/null +++ b/lib/nanolog/src/nanolog.h @@ -0,0 +1,194 @@ +#pragma once +#ifndef __NANOLOG_H__ +#define __NANOLOG_H__ + +#include "Arduino.h" + +// #define LOG(severity, msg) p msg; + +// void p(const char *fmt, ... ) +// { +// static char tmp[128]; // resulting string limited to 128 chars. +// va_list args; +// va_start (args, fmt ); +// vsnprintf(tmp, 128, fmt, args); +// va_end (args); +// Serial.println(tmp); +// delay(1); +// } + +inline void LOG_SPACE_IMPL(); +inline void LOG_SET_IMPL(int8_t i); +inline void LOG_SET_IMPL(int16_t i); +inline void LOG_SET_IMPL(int32_t i); +inline void LOG_SET_IMPL(int64_t i); +inline void LOG_SET_IMPL(uint8_t i); +inline void LOG_SET_IMPL(uint16_t i); +inline void LOG_SET_IMPL(uint32_t i); +inline void LOG_SET_IMPL(uint64_t i); +inline void LOG_SET_IMPL(char c); +inline void LOG_SET_IMPL(String s); +inline void LOG_SET_IMPL(float f); +inline void LOG_SET_IMPL(double d); +inline void LOG_NEW_LINE_IMPL(); + +#ifdef LOG_ENABLED + +#define LOG(P) LOG_SET_IMPL(P) +#define LOG_NEW_LINE LOG_NEW_LINE_IMPL(); +#define LOG_SPACE LOG_SPACE_IMPL() + +#else + +#define LOG(P) +#define LOG_NEW_LINE +#define LOG_SPACE + +#endif + + +inline void LOG_INIT() +{ +#if defined (LOG_ENABLED) + Serial.begin(115200); + LOG("Initialized: SERIAL_LOG64"); + LOG_NEW_LINE; +#endif + +#if defined (EEPROM_LOG_ENABLED) + LOG_EEPROM_READ; + + EEPROM_LOG_ADDR_PTR = EEPROM_LOG_Start_Address; +#endif +} + +inline void LOG_SPACE_IMPL() +{ + Serial.print(" "); +} + +inline void LOG_SET_IMPL(int8_t i) +{ + Serial.print(i); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(int16_t i) +{ + Serial.print(i); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(int32_t i) +{ + Serial.print(i); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(uint8_t i) +{ + Serial.print(i); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(uint16_t i) +{ + Serial.print(i); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(uint32_t i) +{ + Serial.print(i); + LOG_SPACE; +} + + +inline void LOG_SET_IMPL(char c) +{ + Serial.print(c); + LOG_SPACE; +} + + +inline void LOG_SET_IMPL(String s) +{ + Serial.print(s); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(float f) +{ + Serial.print(f); + LOG_SPACE; +} + +inline void LOG_SET_IMPL(double d) +{ + Serial.print(d); + LOG_SPACE; +} + +inline void LOG_NEW_LINE_IMPL() +{ + Serial.println(" "); +} + +inline void LOG_SET_IMPL(uint64_t n) +{ + unsigned char buf[16 * sizeof(long)]; + + if (n == 0) + { + Serial.print((char)'0'); + LOG_SPACE; + return; + } + + for (uint16_t i = 0; n > 0; i++) + { + buf[i] = n % 10; + n /= 10; + } + + for (uint16_t i = 0; i > 0; i--) + { + Serial.print((char) (buf[i - 1] < 10 ? ('0' + buf[i - 1]) : ('A' + buf[i - 1] - 10))); + } + + LOG_SPACE; +} + +inline void LOG_SET_IMPL(int64_t n) +{ + unsigned char buf[16 * sizeof(long)]; ; + + if (n == 0) + { + Serial.print((char)'0'); + LOG_SPACE; + return; + } + + if (n < 0) + { + Serial.print((char)'-'); + n = n * (-1); + } + + for (uint16_t i = 0; n > 0; i++) + { + buf[i] = n % 10; + n /= 10; + } + + for (uint16_t i = 0; i > 0; i--) + { + Serial.print((char) (buf[i - 1] < 10 ? ('0' + buf[i - 1]) : ('A' + buf[i - 1] - 10))); + } + + LOG_SPACE; +} + + +#endif // __NANOLOG_H__ \ No newline at end of file diff --git a/lib/ota/README.md b/lib/ota/README.md new file mode 100755 index 0000000..7dafc88 --- /dev/null +++ b/lib/ota/README.md @@ -0,0 +1,17 @@ +# Over the Air updates + +If you are on Platformio, remember that to use OTA you need to set the upload port and the protocol properly in the `platformio.ini` file. Like: + +``` +; for OTA stuff you have to update the upload_port +upload_protocol = espota +upload_port = IP_ADDRESS_HERE or mDNS_NAME.local +``` + +And remember that you can get serial debug output via telnet using the `TelnetStream` library. + +``` +lib_deps = + TelnetStream +``` + diff --git a/lib/ota/example/otatest.cpp b/lib/ota/example/otatest.cpp new file mode 100755 index 0000000..817541f --- /dev/null +++ b/lib/ota/example/otatest.cpp @@ -0,0 +1,38 @@ +#define LOG_ENABLED +#include +#include +#include +#include + +// i like to put these two in another file, so that it's +// not checked in git commits +#define SSID "some_ssid" +#define PASSWD "some_password" + +void setup() { + Serial.begin(115200); + while(!Serial) ; + + // welcome serial output header + df_header_print(); + + // we need to be connected to wifi for OTA to + // initialize properly + if( wifi_connect_as_client(SSID, PASSWD) ) { + wifi_print_mode(); + wifi_print_ip(); + } else { + Serial.print("Failed to connect to wifi "); + Serial.print( SSID ); + Serial.println(); + } + + // this is the name the device will take as an OTA port + ota_init("racoon"); +} + +void loop() { + ota_loop(); + + delay(100); // chill for a bit +} diff --git a/lib/ota/src/ota.cpp b/lib/ota/src/ota.cpp new file mode 100755 index 0000000..fc104ba --- /dev/null +++ b/lib/ota/src/ota.cpp @@ -0,0 +1,51 @@ +#include "ota.h" + +void ota_init(const char *name = NULL) { + // Port defaults to 3232 + // ArduinoOTA.setPort(3232); + + if(NULL != name) { + // Hostname defaults to esp3232-[MAC] + ArduinoOTA.setHostname( name ); + } + + // No authentication by default + // ArduinoOTA.setPassword("admin"); + + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() + Serial.println("OTA update [" + type + "] begins"); + }) + .onEnd([]() { + Serial.println("\nOTA update ended"); + }) + .onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("OTA update progress: %u%%\r", (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + Serial.printf("OTA update error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + + ArduinoOTA.begin(); +} + + +void ota_loop() { + ArduinoOTA.handle(); +} diff --git a/lib/ota/src/ota.h b/lib/ota/src/ota.h new file mode 100755 index 0000000..72773a4 --- /dev/null +++ b/lib/ota/src/ota.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +void ota_init(const char *name); +void ota_loop(); diff --git a/lib/smoothie/README.md b/lib/smoothie/README.md new file mode 100755 index 0000000..0d17f1d --- /dev/null +++ b/lib/smoothie/README.md @@ -0,0 +1,5 @@ +# Signal smoothing + +A simple library to smooth values from analog readings in microcontroller projects. + + diff --git a/lib/smoothie/example/compare.cpp b/lib/smoothie/example/compare.cpp new file mode 100755 index 0000000..165e863 --- /dev/null +++ b/lib/smoothie/example/compare.cpp @@ -0,0 +1,25 @@ +#include +#include + +Smoothie reading(0.1); + +void setup() { + + Serial.begin( 9600 ); + while(!Serial); + + pinMode(A2, INPUT); +} + +void loop() { + int noisy = analogRead( A2 ); + int avg = analogReadAvg( A2 ); + int val = reading.filter( analogRead( A2 ) ); + + Serial.print( noisy ); + Serial.print(", "); + Serial.print( avg ); + Serial.print(", "); + Serial.print( val ); + Serial.println(); +} \ No newline at end of file diff --git a/lib/smoothie/src/smoothie.cpp b/lib/smoothie/src/smoothie.cpp new file mode 100755 index 0000000..a4b8fa1 --- /dev/null +++ b/lib/smoothie/src/smoothie.cpp @@ -0,0 +1,6 @@ +/** + * Signal smoothing utility functions + * + */ +#include +#include "Smoothie.h" diff --git a/lib/smoothie/src/smoothie.h b/lib/smoothie/src/smoothie.h new file mode 100755 index 0000000..8e91453 --- /dev/null +++ b/lib/smoothie/src/smoothie.h @@ -0,0 +1,44 @@ +#ifndef __SMOOTHIE_H__ +#define __SMOOTHIE_H__ + +/** + * Simple weighed moving average + * from https://makeabilitylab.github.io/physcomp/advancedio/smoothing-input.html + */ +template +class Smoothie { + + float sigma, s; + + public: + Smoothie(float _sigma, float _s = 0); + T filter(T val); +}; + +template +Smoothie::Smoothie(float _sigma, float _s) { + sigma = _sigma; + s = _sigma; +} + +template +T Smoothie::filter(T val) { + s = (sigma * val) + (1 - sigma) * s; + return s; +} + +/// inlined functions + +/// returns the average value of a few consecutive readings +inline int analogReadAvg(int pin, int iter = 4) { + int retval = 0; + + int i = iter; + while(i > 0) { + retval += analogRead( pin ); + } + + return retval / iter; +} // analogReadAvg + +#endif // __SMOOTHIE_H__ \ No newline at end of file diff --git a/lib/ugen/README.md b/lib/ugen/README.md new file mode 100755 index 0000000..cbb850c --- /dev/null +++ b/lib/ugen/README.md @@ -0,0 +1,6 @@ +# Function generators / Oscillators + +Original from Rob Tillart with some minor modifications to fit own personal use. + +Thanks to Rob for the great library! + diff --git a/lib/ugen/examples/duoplot.cpp b/lib/ugen/examples/duoplot.cpp new file mode 100755 index 0000000..8d092df --- /dev/null +++ b/lib/ugen/examples/duoplot.cpp @@ -0,0 +1,35 @@ +#include + +Ugen gen1; +Ugen gen2; + + +void setup() +{ + Serial.begin(115200); + + gen1.setFrequency(13); + gen1.setAmplitude(50); + gen1.setPhase(0); + gen1.setYShift(0); + + gen2.setFrequency(17); + gen2.setAmplitude(25); + gen2.setPhase(0.25); + gen2.setYShift(25); +} + + +void loop() +{ + float t = millis() * 0.001; + float x = gen1.sinus(t); + float y = gen2.sinus(t); + Serial.print(x); + Serial.print("\t"); + Serial.print(y); + Serial.print("\t"); + Serial.print(x + y); + Serial.println(); +} + diff --git a/lib/ugen/src/ugen.cpp b/lib/ugen/src/ugen.cpp new file mode 100755 index 0000000..209070f --- /dev/null +++ b/lib/ugen/src/ugen.cpp @@ -0,0 +1,338 @@ +// +// FILE: functionGenerator.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.2.2 +// PURPOSE: wave form generating functions (use with care) +// URL: https://github.com/RobTillaart/FunctionGenerator +// +// HISTORY: +// 0.1.00 2015-01-01 initial version +// 0.1.01 2015-01-01 initial class version +// 0.1.02 2015-01-01 refactor and research +// 0.1.03 2015-01-02 added stair, more refactoring +// 0.1.04 2015-01-03 added integer versions - to be used with 8 bit DAC +// 0.1.5 2017-07-29 Fix issue #33 (dbl -> float) +// 0.2.0 2020-06-10 main refactoring and cleanup +// 0.2.1 2020-12-24 Arduino-CI + unit tests +// 0.2.2 2021-11-02 update Arduino-CI, badges +// add mode for sawtooth and stair. +// + + +#include "ugen.h" + + +Ugen::Ugen(float period, float amplitude, float phase, float yShift) +{ + setPeriod(period); + setAmplitude(amplitude); + setPhase(phase); + setYShift(yShift); +} + + +void Ugen::setPeriod(float period) +{ + _period = period; + _freq1 = 1 / period; + _freq2 = 2 * _freq1; + _freq4 = 4 * _freq1; + _freq0 = TWO_PI * _freq1; +} + + +float Ugen::line() +{ + return _yShift + _amplitude; +} + + +float Ugen::zero() +{ + return 0; +} + + +float Ugen::sawtooth(float t, uint8_t mode) +{ + float rv; + t += _phase; + if (t >= 0.0) + { + if (t >= _period) t = fmod(t, _period); + if (mode == 1) t = _period - t; + rv = _amplitude * (-1.0 + t *_freq2); + } + else + { + t = -t; + if (t >= _period) t = fmod(t, _period); + if (mode == 1) t = _period - t; + rv = _amplitude * ( 1.0 - t * _freq2); + } + rv += _yShift; + return rv; +} + + +float Ugen::triangle(float t) +{ + float rv; + t += _phase; + if (t < 0.0) + { + t = -t; + } + if (t >= _period) t = fmod(t, _period); + if ( t * 2 < _period) + { + rv = _amplitude * (-1.0 + t * _freq4); + } + else + { + rv = _amplitude * (3.0 - t * _freq4); + } + rv += _yShift; + return rv; +} + + +float Ugen::square(float t) +{ + float rv; + t += _phase; + if (t >= 0) + { + if (t >= _period) t = fmod(t, _period); + if ((t + t) < _period) rv = _amplitude; + else rv = -_amplitude; + } + else + { + t = -t; + if (t >= _period) t = fmod(t, _period); + if ( t * 2 < _period) rv = -_amplitude; + else rv = _amplitude; + } + rv += _yShift; + return rv; +} + + +float Ugen::sinus(float t) +{ + float rv; + t += _phase; + rv = _amplitude * sin(t * _freq0); + rv += _yShift; + return rv; +} + + +float Ugen::stair(float t, uint16_t steps, uint8_t mode) +{ + t += _phase; + if (t >= 0) + { + if (t >= _period) t = fmod(t, _period); + if (mode == 1) t = _period - t; + int level = steps * t / _period; + return _yShift + _amplitude * (-1.0 + 2.0 * level / (steps - 1)); + } + t = -t; + if (t >= _period) t = fmod(t, _period); + if (mode == 1) t = _period - t; + int level = steps * t / _period; + return _yShift + _amplitude * (1.0 - 2.0 * level / (steps - 1)); +} + + +float Ugen::random() +{ + // TODO smart reseed needed + float rv = _yShift + _amplitude * _random() * 0.2328306436E-9; // div 0xFFFFFFFF + return rv; +} + + +// An example of a simple pseudo-random number generator is the +// Multiply-with-carry method invented by George Marsaglia. +// two initializers (not null) +uint32_t Ugen::_random() +{ + _m_z = 36969L * (_m_z & 65535L) + (_m_z >> 16); + _m_w = 18000L * (_m_w & 65535L) + (_m_w >> 16); + return (_m_z << 16) + _m_w; /* 32-bit result */ +} + + +// +// INTEGER VERSIONS FOR 8 BIT DAC +// +// 8 bits version +// t = 0..9999 period 10000 in millis, returns 0..255 + +/* + +uint8_t ifgsaw(uint16_t t, uint16_t period = 1000) +{ + return 255L * t / period; +} + + +uint8_t ifgtri(uint16_t t, uint16_t period = 1000) +{ + if (t * 2 < period) return 510L * t / period; + return 255L - 510L * t / period; +} + + +uint8_t ifgsqr(uint16_t t, uint16_t period = 1000) +{ + if (t * 2 < period) return 510L * t / period; + return 255L - 510L * t / period; +} + + +uint8_t ifgsin(uint16_t t, uint16_t period = 1000) +{ + return sin(355L * t / period / 113); // LUT +} + + +uint8_t ifgstr(uint16_t t, uint16_t period = 1000, uint16_t steps = 8) +{ + int level = 1L * steps * t / period; + return 255L * level / (steps - 1); +} + +*/ + + +// +// SIMPLE float ONES +// +// t = 0..period +// period = 0.001 ... 10000 ? +/* + +float fgsaw(float t, float period = 1.0) +{ + if (t >= 0) return -1.0 + 2 * t / period; + return 1.0 + 2 * t / period; +} + + +float fgtri(float t, float period = 1.0) +{ + if (t < 0) t = -t; + if (t * 2 < period) return -1.0 + 4 * t / period; + return 3.0 - 4 * t / period; +} + + +float fgsqr(float t, float period = 1.0) +{ + if (t >= 0) + { + if ( 2 * t < period) return 1.0; + return -1.0; + } + t = -t; + if (2 * t < period) return -1.0; + return 1.0; +} + + +float fgsin(float t, float period = 1.0) +{ + return sin(TWO_PI * t / period); +} + + +float fgstr(float t, float period = 1.0, uint16_t steps = 8) +{ + if (t >= 0) + { + int level = steps * t / period; + return -1.0 + 2.0 * level / (steps - 1); + } + t = -t; + int level = steps * t / period; + return 1.0 - 2.0 * level / (steps - 1); +} + +*/ + +/* +// +// FULL floatS ONES +// +float fgsaw(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0) +{ + t += phase; + if (t >= 0) + { + if (t >= period) t = fmod(t, period); + return yShift + amplitude * (-1.0 + 2 * t / period); + } + t = -t; + if (t >= period) t = fmod(t, period); + return yShift + amplitude * ( 1.0 - 2 * t / period); +} + + +float fgtri(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, float dutyCycle = 0.50) +{ + t += phase; + if (t < 0) t = -t; + if (t >= period) t = fmod(t, period); + // 50 % dutyCycle = faster + // if (t * 2 < period) return yShift + amplitude * (-1.0 + 4 * t / period); + // return yShift + amplitude * (3.0 - 4 * t / period); + if (t < dutyCycle * period) return yShift + amplitude * (-1.0 + 2 * t / (dutyCycle * period)); + // return yShift + amplitude * (-1.0 + 2 / (1 - dutyCycle) - 2 * t / ((1 - dutyCycle) * period)); + return yShift + amplitude * (-1.0 + 2 / (1 - dutyCycle) * ( 1 - t / period)); +} + + +float fgsqr(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, float dutyCycle = 0.50) +{ + t += phase; + if (t >= 0) + { + if (t >= period) t = fmod(t, period); + if (t < dutyCycle * period) return yShift + amplitude; + return yShift - amplitude; + } + t = -t; + if (t >= period) t = fmod(t, period); + if (t < dutyCycle * period) return yShift - amplitude; + return yShift + amplitude; +} + + +float fgsin(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0) +{ + t += phase; + float rv = yShift + amplitude * sin(TWO_PI * t / period); + return rv; +} + + +float fgstr(float t, float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0, uint16_t steps = 8) +{ + t += phase; + if (t >= 0) + { + if (t >= period) t = fmod(t, period); + int level = steps * t / period; + return yShift + amplitude * (-1.0 + 2.0 * level / (steps - 1)); + } + t = -t; + if (t >= period) t = fmod(t, period); + int level = steps * t / period; + return yShift + amplitude * (1.0 - 2.0 * level / (steps - 1)); +} + +*/ diff --git a/lib/ugen/src/ugen.h b/lib/ugen/src/ugen.h new file mode 100755 index 0000000..8d58095 --- /dev/null +++ b/lib/ugen/src/ugen.h @@ -0,0 +1,57 @@ +#pragma once +// +// FILE: functionGenerator.h +// AUTHOR: Rob Tillaart +// VERSION: 0.2.2 +// PURPOSE: wave form generating functions (use with care) +// URL: https://github.com/RobTillaart/FunctionGenerator +// + + +#include "Arduino.h" + +class Ugen +{ +public: + Ugen(float period = 1.0, float amplitude = 1.0, float phase = 0.0, float yShift = 0.0); + + // configuration + void setPeriod(float period = 1.0); + float getPeriod() { return _period; }; + void setFrequency(float freq = 1.0) { setPeriod(1/freq); }; + float getFrequency() { return _freq1; }; + + void setAmplitude(float ampl = 1.0) { _amplitude = ampl; }; + float getAmplitude() { return _amplitude; }; + void setPhase(float phase = 0.0) { _phase = phase; }; + float getPhase() { return _phase; }; + void setYShift(float yShift = 0.0) { _yShift = yShift; }; + float getYShift() { return _yShift; }; + + // constant amplitude + float line(); + // constant zero for calibration + float zero(); + + // standard wave forms + float sawtooth(float t, uint8_t mode = 0); + float triangle(float t); + float square(float t); + float sinus(float t); + float stair(float t, uint16_t steps = 8, uint8_t mode = 0); + float random(); + +private: + float _period; + float _freq0; + float _freq1; + float _freq2; + float _freq4; + float _amplitude; + float _phase; + float _yShift; + // Marsaglia 'constants' + uint32_t _m_w = 1; + uint32_t _m_z = 2; + uint32_t _random(); +}; diff --git a/platformio.ini b/platformio.ini index 1238fc1..ba3178a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,6 +22,8 @@ lib_deps = SoftwareSerial=https://github.com/plerup/espsoftwareserial/archive/refs/tags/6.16.1.zip Time=paulstoffregen/Time@^1.6.1 ESP32Servo=https://github.com/madhephaestus/ESP32Servo/archive/refs/tags/0.10.0.zip + MQTT = https://github.com/256dpi/arduino-mqtt + ; NeoGPS=slashdevin/NeoGPS@^4.2.9 ; SolarPosition=https://github.com/KenWillmott/SolarPosition.git diff --git a/src/main.cpp b/src/main.cpp index c2c2ab7..5f45771 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,32 @@ #include +#if defined(ARDUINO_ARCH_ESP32) +#include #include +#else +#include +#endif #include #include #include #include +#include +#include +#include "settings.h" + #include #include #include #include +// the name of this device, we start with "unknown" and we will later generate one +String deviceId = "unknown"; +WiFiClient net; +MQTTClient client(net); + #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 @@ -75,15 +89,67 @@ void init_servo() { servo.attach(servoPin, 500, 2400); } +void init_wifi() { + // connect to existing wifi access point as client + if( wifi_connect_as_client(WIFI_SSID, WIFI_PASSWORD) ) { + // print debugging information + wifi_print_mode(); + wifi_print_ip(); // print our known ip address + } else { + Serial.print("Failed to connect to wifi "); + Serial.print( WIFI_SSID ); + Serial.println(); + } +} + +void mqtt_on_message(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void mqtt_connect() { + while (!client.connect(deviceId.c_str(), MQTT_BROKER_USER, MQTT_BROKER_PASS)) { // MQTT_DEVICE_ID, + Serial.print("."); + delay(1000); + } + + client.begin(MQTT_BROKER, MQTT_PORT, net); + client.onMessage(mqtt_on_message); +} + +/// create a random client ID +String mqtt_make_device_id() { + String retval; + + // ESP32 version + uint64_t macAddress = ESP.getEfuseMac(); + uint64_t macAddressTrunc = macAddress << 40; + uint64_t chipid = macAddressTrunc >> 40; + + // this makes a random ID on every run, nice, but we don't really want that + // retval = String((int)chipid, HEX) + "-" + String(random(0xffff), HEX); + + // so we make an ID that is bound to the device and stays the same on every run + // and we give it a fixed prefix so we can find all of our devices when we need them + retval = String("qi-") + String((int)chipid, HEX); + + return retval; +} + // /////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(115200); + while(!Serial) ; + init_servo(); init_display(); init_gps(); wmm_init(); + + deviceId = mqtt_make_device_id(); + init_wifi(); + mqtt_connect(); } void ui_nogpsfix() { diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..b4f804d --- /dev/null +++ b/src/settings.h @@ -0,0 +1,14 @@ +#ifndef __SETTINGS_H__ +#define __SETTINGS_H__ + +// wifi credentials +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +//#define MQTT_DEVICE_ID "" +#define MQTT_BROKER_USER "" +#define MQTT_BROKER_PASS "" +#define MQTT_BROKER "" +#define MQTT_PORT "" + +#endif // __SETTINGS_H__ \ No newline at end of file