Latest Version with all features enabled

This commit is contained in:
Jens Noack 2023-02-14 09:33:00 +01:00
parent 51ad765581
commit d113c1b1f7
13 changed files with 1206 additions and 75 deletions

View file

@ -0,0 +1,33 @@
{
"svn.ignoreMissingSvnWarning": true,
"files.associations": {
"typeinfo": "cpp",
"*.tcc": "cpp",
"chrono": "cpp",
"ctime": "cpp",
"iomanip": "cpp",
"limits": "cpp",
"numeric": "cpp",
"ratio": "cpp",
"streambuf": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"array": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"random": "cpp",
"system_error": "cpp",
"cmath": "cpp",
"fstream": "cpp",
"istream": "cpp",
"ostream": "cpp",
"thread": "cpp",
"regex": "cpp"
}
}

View file

@ -0,0 +1,27 @@
#ifndef CAPPORTAL_HPP
#define CAPPORTAL_HPP
#include <WiFi.h> // Replace with WiFi.h for ESP32
#include <WebServer.h> // Replace with WebServer.h for ESP32
#include <AutoConnect.h>
#include "time.h"
extern String html_content;
class Cap{
private:
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600;
const int daylightOffset_sec = 3600;
AutoConnect *Portal;
AutoConnectConfig *Config;
public:
void begin();
void handle();
unsigned long epochTime();
String localTime();
String localTime(time_t epochtime);
String localIP();
};
#endif //CAPPORTAL_HPP

View file

@ -0,0 +1,55 @@
#ifndef __eeprom_H__
#define __eeprom_H__
#include <TridentTD_ESP32NVS.h>
class Eeprom
{
private:
public:
Eeprom();
~Eeprom();
void set_int(String name , uint64_t val );
void set_int_period(String name , uint64_t val , time_t period_ms);
uint64_t get_int(String name );
void begin();
};
Eeprom::Eeprom()
{
}
Eeprom::~Eeprom()
{
}
void Eeprom::begin()
{
Serial.println("Init EEPROM ...");
NVS.begin();
}
void Eeprom::set_int_period(String name , uint64_t val , time_t period_ms)
{
static time_t last_stored_ms = 0;
if((last_stored_ms == 0) || ((millis() - last_stored_ms) > period_ms))
{
last_stored_ms = millis();
set_int(name , val );
}
}
void Eeprom::set_int(String name , uint64_t val )
{
if(NVS.getInt(name) != val)
{
NVS.setInt(name, val);
}
}
uint64_t Eeprom::get_int(String name )
{
return NVS.getInt(name);
}
#endif

View file

@ -0,0 +1,29 @@
#ifndef JSON_HPP
#define JSON_HPP
#include <ArduinoJson.h>
#include <map>
#include <string>
typedef struct
{
const char * name;
unsigned long ticks;
unsigned long period_ticks;
const char * unit;
double value;
float unit_factor;
unsigned long last_update_ms;
unsigned long timestamp;
} DataStruct;
const uint8_t NR_JSON_SECTION_OBJECTS = 8;
class Myjson{
private:
public:
String create_json_string(volatile DataStruct *data_struct, size_t nr_dataobjects, time_t runtime_s);
};
#endif //JSON_HPP

View file

@ -0,0 +1,106 @@
#ifndef MAIN_HPP
#define MAIN_HPP
#define MACHINE_RESTART
//#define DUMMY_DATA
#define EEPROM_NAME_TICK "hall_tick"
#define EEPROM_NAME_TIMESTAMP "timestamp"
#define EEPROM_NAME_RUN_TIME "runtime"
#define EEPROM_NAME_START_EPOCHTIME "starttime"
#define EEPROM_STORE_RUNTIME_ALL_MS 1000 * 60 //* 5
#include <NTPClient.h>
#include <ESP32Servo.h>
#include <Arduino.h>
#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier
#include "eeprom.hpp"
#include "oled.hpp"
#include "capportal.hpp"
#define HAS_MQTT
#ifdef HAS_MQTT
#include "mqtt.hpp"
#include "json.hpp"
Mymqtt mqtt;
Myjson json;
/*makerlab*/
const char* mqttServer = "mqtt.makerlab-murnau.de";
const int mqttPort = 8883;
const char* mqttUser = "";
const char* mqttPassword = "";
/*hivemq*/
/*
const char* mqttServer = "ccb0edef424149d4b3d2ee2ee503b87d.s1.eu.hivemq.cloud";
const int mqttPort = 8883;
const char* mqttUser = "infinity";
const char* mqttPassword = "12345678";
*/
#endif
WiFiUDP ntpUDP;
//NTPClient timeClient(ntpUDP);
NTPClient timeClient( ntpUDP,"pool.ntp.org", 3600);
// Variables to save date and time
String timeStamp;
Eeprom Store;
Cap capportal;
Servo ESC; // Der ESC-Controller (Electronic Speed Controller bzw. elektronischer Fahrtregler) wird als Objekt mit dem Namen "ESC" festgelegt.
Oled display;
const unsigned long UPDATE_TURN_VALUES_EVERY_MS = 1000;
const uint8_t HALL_SENSORS_COUNT = 8; // input, sec, min, hour, day, week, month, year
const uint8_t ALL_DATA_COUNT = HALL_SENSORS_COUNT;
const uint8_t HALL_TICKS_PER_TURN = 4;
const uint8_t HALL_MIN_PULSE_MS = 50;
volatile DataStruct AllData[ALL_DATA_COUNT];
volatile DataStruct *HallData = AllData;
const char *Data_names[ALL_DATA_COUNT] =
{
// Hall sensors
"cascade_input", "cascade_sec", "cascade_min", "cascade_hour", "cascade_day", "cascade_week", "cascade_month", "cascade_year",
};
const char *Data_units[ALL_DATA_COUNT] =
{
// Hall sensors
"U/min", "sec", "min", "hour", "day", "week", "month", "year",
};
const float Data_units_factor[ALL_DATA_COUNT] =
{
//Hall sensors
(60000.0/UPDATE_TURN_VALUES_EVERY_MS)/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN, 1.0/HALL_TICKS_PER_TURN
};
const char ** Hall_names = Data_names;
const char ** Hall_units = Data_units;
const float * Hall_units_factor = Data_units_factor;
const uint8_t LED_BUILTIN = 2;
const uint8_t POTI_PIN = 36; // never use ADC2 (GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27) if Wifi is active ... use ADC1 instead (GPIO32-GPIO39)
const uint8_t ESC_PIN = 16;
const uint8_t HALL1_PIN = 34;
const uint8_t HALL2_PIN = 35;
const uint8_t HALL3_PIN = 32;
const uint8_t HALL4_PIN = 33;
const uint8_t HALL5_PIN = 25;
const uint8_t HALL6_PIN = 26;
const uint8_t HALL7_PIN = 27;
const uint8_t HALL8_PIN = 14;
const uint8_t MAX_ESC_SPEED = 60;
const uint8_t MIN_ESC_SPEED = 35;
const uint16_t MAX_POTI_VALUE = 4095;
const uint16_t JITTER_POTI_PERCENT = 10;
#endif //MAIN_HPP

View file

@ -0,0 +1,75 @@
#ifndef MQTT_HPP
#define MQTT_HPP
#include <WiFi.h> // Replace with WiFi.h for ESP32
//#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
static const char *root_ca PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)EOF";
#define MQTT_TRY_TO_CONNECT_MS 2000
#define MQTT_CHANNEL "infinitymachine"
#define MQTT_BUFFER_SIZE 1024
#define SEND_MQTT_EVERY_MS 1000
class Mymqtt
{
private:
WiFiClientSecure *espClient;
PubSubClient *client;
String _server = "";
uint16_t _port = 0;
String _mqttUser = "";
String _mqttPassword = "";
String _data_sent = "";
public:
void begin(const char * server, uint16_t mqttPort, const char* mqttUser, const char* mqttPassword);
bool connect();
bool is_connected();
bool publish(String topic,String data);
bool send_and_loop(String topic,String data);
bool loop();
//void callback(char* topic, byte* payload, unsigned int length);
};
#endif //MQTT_HPP

View file

@ -0,0 +1,43 @@
#ifndef OLED_HPP
#define OLED_HPP
#include "SSD1306Wire.h" // legacy: #include "SSD1306.h"
#include "json.hpp"
#include <Arduino.h>
class Oled
{
private:
const unsigned long PAGE_VIEW_TIME_MS = 10000;
const uint8_t HALLS_PER_PAGE = 4;
const uint8_t MAX_PAGE_NR = HALL2;
const uint8_t MIN_PAGE_NR = SPEED;
enum pages {SPEED, HALL1, HALL2};
//SSD1306Wire display(0x3c, SDA, SCL);
SSD1306Wire *display;
uint8_t xpos = 0;
uint8_t ypos = 0;
pages page = SPEED;
uint8_t page_nr = MIN_PAGE_NR;
void next_page(bool speedchange);
void show_page_header( String ipaddr, pages page);
void show_speed(int speed, int min_speed, int max_speed, double u_min, unsigned long runtime, pages page);
void show_halls(volatile DataStruct *HallData, uint8_t hall_sensor_count, pages page);
void show_page_footer(pages page);
public:
void begin();
void progressBar(uint8_t i);
void show_values(int speed, int min_speed, int max_speed, volatile DataStruct *HallData, uint8_t hall_sensors_count, unsigned long runtime, String ipaddr);
};
#endif //OLED_HPP

View file

@ -9,9 +9,16 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:esp32] [env:esp32]
monitor_speed = 115200
platform = espressif32 platform = espressif32
board = esp32dev board = esp32dev
framework = arduino framework = arduino
lib_deps = lib_deps =
thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.1 thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.1
madhephaestus/ESP32Servo@^0.11.0 madhephaestus/ESP32Servo@^0.11.0
tridenttd/TridentTD_ESP32NVS@^1.0
hieromon/AutoConnect@^1.4.0
knolleary/PubSubClient@^2.8
bblanchon/ArduinoJson@^6.19.4
arduino-libraries/NTPClient@^3.2.1
paulstoffregen/Time@^1.6.1

View file

@ -0,0 +1,85 @@
#include "capportal.hpp"
#include <TimeLib.h>
WebServer CapServer;
String html_content = "";
static void rootPage() {
CapServer.send(302, "text/html", html_content);
}
void Cap::begin() {
Portal = new AutoConnect(CapServer);
Config = new AutoConnectConfig();
Config->autoReset = false; // Not reset the module even by intentional disconnection using AutoConnect menu.
Config->portalTimeout = 1000; // Do not block the sketch and exit after 1000ms
//Config->immediateStart = true;
Config->autoReconnect = true; // Reconnect to known access points.
Config->reconnectInterval = 6; // Reconnection attempting interval is 3[min].
Config->retainPortal = true; // Keep the captive portal open.
Config->apid = "Unendlichkeit_AP";
Config->menuItems = Config->menuItems | AC_MENUITEM_UPDATE;
Config->hostName = "Unendlichkeit";
Config->ota = AC_OTA_BUILTIN;
Portal->config(*Config);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
//content = "<!DOCTYPE html><html><head><meta http-equiv=\"refresh\" content=\"0; url='/_ac'\" /></head><body></body></html>";
CapServer.on("/", rootPage);
if (Portal->begin()) {
Serial.println("WiFi connected: " + WiFi.localIP().toString());
}
else{
Serial.println("No configured Wifi connection. Connect to '" + Config->apid + "' and configure network connections.");
}
}
String Cap::localIP()
{
return WiFi.localIP().toString();
}
void Cap::handle(){
Portal->handleClient();
}
// Function that gets current epoch time
unsigned long Cap::epochTime() {
time_t now;
struct tm timeinfo;
if ( !getLocalTime(&timeinfo)) {
//Serial.println("Failed to obtain time");
return(0);
}
time(&now);
//Serial.printf("Epochtime: %lu\n", now);
return now;
}
String Cap::localTime(){
String dateTime = "";
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
//Serial.println("Failed to obtain time");
return(dateTime);
}
//Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
dateTime = String(timeinfo.tm_year + 1900) + "-" + String(timeinfo.tm_mon + 1) + "-" + String(timeinfo.tm_mday) + "+" + String(timeinfo.tm_hour) + ":" + String(timeinfo.tm_min) + ":" + String(timeinfo.tm_sec);
//Serial.printf("%s\n", dateTime.c_str());
return(dateTime);
}
String Cap::localTime(time_t epochtime){
String dateTime = "";
dateTime = String(year(epochtime)) + "-" + String(month(epochtime)) + "-" + String(day(epochtime)) + "+" + String(hour(epochtime)) + ":" + String(minute(epochtime)) + ":" + String(second(epochtime));
Serial.printf("%s\n", dateTime.c_str());
return(dateTime);
}

View file

@ -0,0 +1,28 @@
#include "json.hpp"
String Myjson::create_json_string(volatile DataStruct *data_struct, size_t nr_dataobjects, time_t runtime_sec)
{
static unsigned long last_send_ms = 0;
unsigned int _sections = nr_dataobjects; //number of different values
const unsigned int _sec_objects = NR_JSON_SECTION_OBJECTS; //number of objects per value
const unsigned int _obj_members = 5; //number of members per object
String json_str = "";
int _capacity = JSON_ARRAY_SIZE(_sections) + _sec_objects*JSON_OBJECT_SIZE(_obj_members);
DynamicJsonDocument _doc(_capacity + 100);
_doc["runtime_s"] = runtime_sec;
JsonObject _doc_object[_sections];
for(unsigned int section_nr = 0; section_nr < _sections; section_nr++)
{
_doc_object[section_nr] = _doc.createNestedObject(data_struct[section_nr].name);
_doc_object[section_nr]["ticks"] = data_struct[section_nr].ticks;
_doc_object[section_nr]["value"] = data_struct[section_nr].value;
_doc_object[section_nr]["unit"] = data_struct[section_nr].unit;
_doc_object[section_nr]["timestamp"] = data_struct[section_nr].timestamp;
}
int nr_bytes = serializeJson(_doc, json_str);
return(json_str);
}

View file

@ -1,115 +1,390 @@
#include <ESP32Servo.h> #include "main.hpp"
#include <Arduino.h>
#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy: #include "SSD1306.h"
SSD1306Wire display(0x3c, SDA, SCL);
Servo ESC; // Der ESC-Controller (Electronic Speed Controller bzw. elektronischer Fahrtregler) wird als Objekt mit dem Namen "ESC" festgelegt.
int Drehregler; // Ausgabewert des Drehreglers int Drehregler; // Ausgabewert des Drehreglers
int speed, last_speed; // Das Wort "Geschwindigkeit" steht als Variable für den Ansteuerungswert am ESC. int speed; // Das Wort "Geschwindigkeit" steht als Variable für den Ansteuerungswert am ESC.
unsigned long turn = 0; int last_speed;
unsigned long speedturns = 0;
unsigned long speedchanged_ms = 0;
unsigned long speed_u_per_min = 0;
const uint8_t LED_BUILTIN = 2; time_t run_time = 0;
const uint8_t POTI_PIN = 4; time_t start_time = 0;
const uint8_t ESC_PIN = 16;
const uint8_t LS1_PIN = 14;
const uint8_t MAX_ESC_SPEED = 60; void ISR_HALL1();
const uint8_t MIN_ESC_SPEED = 35; void ISR_HALL2();
const uint16_t MAX_POTI_VALUE = 4095; void ISR_HALL3();
void ISR_HALL4();
void ISR_HALL5();
void ISR_HALL6();
void ISR_HALL7();
void ISR_HALL8();
void show_values(); void data_generate();
void ISR(); void data_store();
void data_check();
void data_init();
void speed_set();
void count_secs(time_t* run_time);
#ifdef HAS_MQTT
void json_init();
#endif
void setup() void setup()
{ {
Serial.begin(9600); delay(1000);
// Initialising the UI will init the display too. Serial.begin(115200);
display.init(); Serial.println("Init capture portal ...");
display.clear();
display.flipScreenVertically(); randomSeed(micros());
//display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_CENTER); display.begin();
display.setFont(ArialMT_Plain_24); capportal.begin();
display.setFont(ArialMT_Plain_16); html_content = "<!DOCTYPE html><html><head><meta http-equiv=\"refresh\" content=\"0; url='/_ac'\" /></head><body></body></html>";
display.drawString(64, 2, "Init controller");
display.setFont(ArialMT_Plain_10); #ifdef HAS_MQTT
display.drawString(64, 40, "You may hear some beeps."); mqtt.begin(mqttServer, mqttPort, mqttUser, mqttPassword);
display.drawString(64, 52, "That's OK! ;-)"); #endif
display.display();
display.setTextAlignment(TEXT_ALIGN_LEFT); Store.begin();
display.setFont(ArialMT_Plain_16); data_init();
Serial.println("Init ETC ...");
ESC.attach(ESC_PIN,1000,2000); ESC.attach(ESC_PIN,1000,2000);
for(uint8_t i=0;i<=100;i=i+10) for(uint8_t i=0;i<=100;i=i+10)
{ {
display.drawProgressBar(6, 28, 116, 6, i); display.progressBar(i);
delay(500); delay(500);
ESC.write(0); ESC.write(0);
display.display();
} }
attachInterrupt(LS1_PIN, ISR, RISING); pinMode(39, INPUT_PULLDOWN);
pinMode(HALL1_PIN, INPUT);
pinMode(HALL2_PIN, INPUT);
pinMode(HALL3_PIN, INPUT);
pinMode(HALL4_PIN, INPUT);
pinMode(HALL5_PIN, INPUT);
pinMode(HALL6_PIN, INPUT);
pinMode(HALL7_PIN, INPUT);
pinMode(HALL8_PIN, INPUT);
last_speed = 0;
speed = 0;
//Serial.println("Init light sensor interrupt ...");
//attachInterrupt(LS1_PIN, ISR_LS1, RISING);
Serial.println("Init hall sensor interrupts ...");
attachInterrupt(digitalPinToInterrupt(HALL1_PIN), ISR_HALL1, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL2_PIN), ISR_HALL2, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL3_PIN), ISR_HALL3, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL4_PIN), ISR_HALL4, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL5_PIN), ISR_HALL5, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL6_PIN), ISR_HALL6, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL7_PIN), ISR_HALL7, FALLING);
attachInterrupt(digitalPinToInterrupt(HALL8_PIN), ISR_HALL8, FALLING);
Serial.println(" Auf gehts ... ");
} }
void loop() void loop()
{ {
capportal.handle();
data_generate();
count_secs(&run_time);
speed_set();
data_check();
data_store();
#ifdef HAS_MQTT
mqtt.send_and_loop("infinity/data", json.create_json_string(AllData, ALL_DATA_COUNT, run_time));
#endif
display.show_values(speed, MIN_ESC_SPEED, MAX_ESC_SPEED, HallData, HALL_SENSORS_COUNT, run_time, capportal.localIP());
}
void count_secs(time_t* run_time)
{
static time_t last_update_ms = 0;
if(last_update_ms == 0)
{
last_update_ms = millis();
}
if(millis() - last_update_ms >= 1000)
{
last_update_ms = millis();
*run_time = *run_time + 1;
}
}
void speed_set()
{
static uint8_t _count_meas = 0;
static int _Drehregler = 0;
static unsigned long _last_read_ms = 0;
if( millis() - _last_read_ms > 25)
{
_last_read_ms = millis();
int maxDrehregler = 0;
int minDrehregler = 0;
int sumDrehregler = 0;
for(uint8_t i = 0; i<6;i++)
{
Drehregler = analogRead(POTI_PIN); // Dieser Befehl liest den Wert des Potentiometers am analogen Pin A0 aus und speichert ihn unter der Variablen "Drehregler". Der Wert liegt zwischen 0 und 1023. Drehregler = analogRead(POTI_PIN); // Dieser Befehl liest den Wert des Potentiometers am analogen Pin A0 aus und speichert ihn unter der Variablen "Drehregler". Der Wert liegt zwischen 0 und 1023.
if(i==0)
{
maxDrehregler = Drehregler;
minDrehregler = Drehregler;
}
else
{
if(Drehregler < minDrehregler)
{
minDrehregler = Drehregler;
}
if(Drehregler > maxDrehregler)
{
maxDrehregler = Drehregler;
}
}
sumDrehregler = sumDrehregler + Drehregler;
}
sumDrehregler = sumDrehregler - maxDrehregler - minDrehregler;
sumDrehregler = sumDrehregler/4;
speed = map(sumDrehregler, 0, MAX_POTI_VALUE, MIN_ESC_SPEED, MAX_ESC_SPEED); // Der "MAP-" Befehl wandelt den Messwert aus der Variablen "Drehregler" um, damit er am ESC verarbeitet werden kann. Der Zahlenbereich 0 bis 1023 wird dabei in einen Zahlenwert zwischen 0 und 180 umgewandelt.
/*
if(abs(Drehregler - _Drehregler) < ((_Drehregler * JITTER_POTI_PERCENT)/100) )
{
_count_meas++;
}
else
{
_count_meas = 0;
}
_Drehregler = Drehregler;
if(_count_meas >= 4)
{
_count_meas >= 0;
speed = map(Drehregler, 0, MAX_POTI_VALUE, MIN_ESC_SPEED, MAX_ESC_SPEED); // Der "MAP-" Befehl wandelt den Messwert aus der Variablen "Drehregler" um, damit er am ESC verarbeitet werden kann. Der Zahlenbereich 0 bis 1023 wird dabei in einen Zahlenwert zwischen 0 und 180 umgewandelt. speed = map(Drehregler, 0, MAX_POTI_VALUE, MIN_ESC_SPEED, MAX_ESC_SPEED); // Der "MAP-" Befehl wandelt den Messwert aus der Variablen "Drehregler" um, damit er am ESC verarbeitet werden kann. Der Zahlenbereich 0 bis 1023 wird dabei in einen Zahlenwert zwischen 0 und 180 umgewandelt.
if(speed != last_speed) }
{ */
last_speed = speed;
speedchanged_ms = millis();
speedturns = 0;
} }
if(millis() - speedchanged_ms > 10000)
{
speed_u_per_min = (speedturns*6);
speedturns = 0;
speedchanged_ms = millis();
}
//Serial.print("Drehregler:"); Serial.print(Drehregler); Serial.print(", Speed:");Serial.println(speed);
if(MIN_ESC_SPEED < speed) if(MIN_ESC_SPEED < speed)
ESC.write(speed); // Der endgültige Wert für den ESC wird an den ESC gesendet. Der ESC nimmt das Signal an dieser Stelle auf und steuert den Motor entsprechend der gesendeten Werte an. ESC.write(speed); // Der endgültige Wert für den ESC wird an den ESC gesendet. Der ESC nimmt das Signal an dieser Stelle auf und steuert den Motor entsprechend der gesendeten Werte an.
else else
ESC.write(0); ESC.write(0);
show_values();
} }
void show_values() void data_init()
{ {
display.clear(); Serial.println("Init internal data ...");
display.setTextAlignment(TEXT_ALIGN_LEFT); #ifdef MACHINE_RESTART
display.setFont(ArialMT_Plain_10); run_time = 0;
display.drawString(1, 1, "Speed:"); start_time = capportal.epochTime();
display.drawProgressBar(40, 4, 80, 6, map(speed, MIN_ESC_SPEED,MAX_ESC_SPEED,0,100)); Store.set_int(EEPROM_NAME_RUN_TIME , run_time );
display.setFont(ArialMT_Plain_10); Store.set_int(EEPROM_NAME_START_EPOCHTIME, start_time );
display.drawString(1, 15, "Turns:"); Serial.printf("Machine restarted. Set runtime to 0. Stored this value and the epoch start time %lu to EEPROM.\n", start_time);
display.drawString(35, 15, String(turn)); #else
display.setFont(ArialMT_Plain_24); run_time = Store.get_int(EEPROM_NAME_RUN_TIME );
display.setTextAlignment(TEXT_ALIGN_RIGHT); start_time = Store.get_int(EEPROM_NAME_START_EPOCHTIME );
display.drawString(64, 37, String(speed_u_per_min)); Serial.printf("Machine runtime loaded from EPPROM: %lu seconds. Machine was started %s\n", run_time, capportal.localTime(start_time));
display.setTextAlignment(TEXT_ALIGN_LEFT); #endif
display.drawString(68,37, "U/min"); last_speed = 0;
display.display(); speed = 0;
for (uint8_t i = 0; i < ALL_DATA_COUNT; i ++)
{
AllData[i].name = Data_names[i];
AllData[i].unit = Data_units[i];
AllData[i].value = 0;
AllData[i].unit_factor = Data_units_factor[i];
AllData[i].period_ticks = 0;
#ifdef MACHINE_RESTART
AllData[i].ticks = 0;
#else
AllData[i].ticks = Store.get_int(EEPROM_NAME_TICK+String(i));
AllData[i].timestamp = Store.get_int(EEPROM_NAME_TIMESTAMP+String(i));
#endif
AllData[i].last_update_ms = 0;
AllData[i].timestamp = 0;
}
delay(500);
} }
void IRAM_ATTR ISR() void data_check()
{ {
turn++; static unsigned long speedchanged_ms ;
speedturns++; unsigned long current_millis = millis();
Serial.printf("H1(pin %d): %d, H2(pin %d): %d, H3(pin %d): %d, H4(pin %d): %d, H5(pin %d) : %d, H6(pin %d) : %d, H7(pin %d) : %d, H8(pin %d) : %d.\n",
HALL1_PIN, digitalRead(HALL1_PIN),
HALL2_PIN, digitalRead(HALL2_PIN),
HALL3_PIN, digitalRead(HALL3_PIN),
HALL4_PIN, digitalRead(HALL4_PIN),
HALL5_PIN, digitalRead(HALL5_PIN),
HALL6_PIN, digitalRead(HALL6_PIN),
HALL7_PIN, digitalRead(HALL7_PIN),
HALL8_PIN, digitalRead(HALL8_PIN)
);
if(speed != last_speed)
{
last_speed = speed;
speedchanged_ms = current_millis;
HallData[0].period_ticks = 0;
}
else
{
if(current_millis - speedchanged_ms > UPDATE_TURN_VALUES_EVERY_MS)
{
speedchanged_ms = current_millis;
HallData[0].value = (HallData[0].period_ticks * HallData[0].unit_factor);
HallData[0].period_ticks = 0;
}
}
for(uint8_t nr = 1; nr < HALL_SENSORS_COUNT; nr++)
{
HallData[nr].value = (HallData[nr].ticks * HallData[nr].unit_factor);
HallData[nr].period_ticks = 0;
}
} }
void data_store()
{
static unsigned long _last_stored_ms = 0;
if(_last_stored_ms == 0)
{
_last_stored_ms = millis();
}
if(millis() - _last_stored_ms >= EEPROM_STORE_RUNTIME_ALL_MS)
{
_last_stored_ms = millis();
Store.set_int(EEPROM_NAME_RUN_TIME, run_time);
for(uint8_t nr = 0; nr < HALL_SENSORS_COUNT; nr++)
{
Store.set_int(EEPROM_NAME_TICK+String(nr), HallData[nr].ticks);
Store.set_int(EEPROM_NAME_TIMESTAMP+String(nr), HallData[nr].timestamp);
}
}
}
void IRAM_ATTR ISR_HALL1()
{
const uint8_t hallnr = 0;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL2()
{
const uint8_t hallnr = 1;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL3()
{
const uint8_t hallnr = 2;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL4()
{
const uint8_t hallnr = 3;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL5()
{
const uint8_t hallnr = 4;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL6()
{
const uint8_t hallnr = 5;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL7()
{
const uint8_t hallnr = 6;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
void IRAM_ATTR ISR_HALL8()
{
const uint8_t hallnr = 7;
HallData[hallnr].ticks++;
HallData[hallnr].period_ticks++;
HallData[hallnr].timestamp = run_time;
HallData[hallnr].last_update_ms = millis();
}
//this code is just for generating dummy data - in normal use not needed
void data_generate()
{
#ifdef DUMMY_DATA
static unsigned long _last_updated_ms = 0;
unsigned long _wait_ms = map(speed, MIN_ESC_SPEED, MAX_ESC_SPEED, 60000/500/4, 60000/1500/4);
//Serial.printf("Speed is : %lu and _wait_ms is %lu\n", speed, _wait_ms);
if(_last_updated_ms == 0)
{
_last_updated_ms = millis();
}
if(millis() - _last_updated_ms >= _wait_ms )
{
_last_updated_ms = millis();
for(uint8_t i = 0; i < HALL_SENSORS_COUNT; i++)
{
if(i == 0)
{
HallData[i].ticks++;
HallData[i].period_ticks++;
HallData[i].last_update_ms = millis();
HallData[i].timestamp = run_time;
}
else
{
//Serial.printf("i=%d HallData[i-1].ticks=%lu %4 = %d\n" , i, HallData[i-1].ticks , HallData[i-1].ticks % 4);
if (HallData[i].last_update_ms != HallData[i-1].last_update_ms && HallData[i-1].ticks % 4 == 0)
{
HallData[i].ticks++;
HallData[i].period_ticks++;
HallData[i].last_update_ms = HallData[i-1].last_update_ms;
HallData[i].timestamp = run_time;
}
}
}
}
#endif
}

View file

@ -0,0 +1,131 @@
#include "mqtt.hpp"
void Mymqtt::begin(const char * server, uint16_t mqttPort, const char* mqttUser, const char* mqttPassword)
{
_server = server;
_port = mqttPort;
_mqttPassword = mqttPassword;
_mqttUser = mqttUser;
espClient = new WiFiClientSecure();//new WiFiClient();
client = new PubSubClient(*espClient);
client->setBufferSize(MQTT_BUFFER_SIZE);
}
void callback(char* topic, byte* payload, unsigned int length) {
String incommingMessage = "";
for (int i = 0; i < length; i++) incommingMessage+=(char)payload[i];
Serial.println("Message arrived ["+String(topic)+"]"+incommingMessage);
// check for other commands
/* else if( strcmp(topic,command2_topic) == 0){
if (incommingMessage.equals(1)) { } // do something else
}
*/
}
bool Mymqtt::connect()
{
static unsigned long last_connection_try_ms = 0;
unsigned long start_ms = 0;
if(true == is_connected())
{
return true;
}
if((last_connection_try_ms == 0) || (millis() - last_connection_try_ms > MQTT_TRY_TO_CONNECT_MS))
{
last_connection_try_ms = millis();
if (WiFi.status() == WL_CONNECTED)
{
Serial.printf("(Re)connecting to MQTT ... server '%s' port: %d \n", _server.c_str(), _port);
espClient->setCACert(root_ca);
client->setServer(_server.c_str(), _port);
client->setCallback(callback);
start_ms = millis();
String clientId = MQTT_CHANNEL "-"; // Create a random client ID
clientId += String(random(0xffff), HEX);
if (client->connect(MQTT_CHANNEL, _mqttUser.c_str(), _mqttPassword.c_str()))
{
Serial.println(" -> MQTT connected");
String connect_msg = "Connected from Infinitymachine of MakerLab Murnau e.V at " + String(millis());
if(client->publish("infinity/connected", connect_msg.c_str()))
{
Serial.println("Connection and initial publish passed.");
}
else
{
Serial.println("Connection and initial publish FAILED.");
}
}
else
{
Serial.print(" -> MQTT connection failed with state ");
Serial.println(client->state());
}
}
else
{
Serial.println("Not connected to the WiFi network");
}
}
return(is_connected());
}
bool Mymqtt::is_connected()
{
return(client->connected());
}
bool Mymqtt::publish(String topic,String data)
{
if(true == connect())
{
client->publish(topic.c_str(), data.c_str(), true);
return(true);
}
return(false);
}
bool Mymqtt::loop()
{
if(true == connect())
{
client->loop();
return(true);
}
return(false);
}
bool Mymqtt::send_and_loop(String topic,String data)
{
static unsigned long _last_sent_ms = 0;
if(millis() - _last_sent_ms >= SEND_MQTT_EVERY_MS)
{
_last_sent_ms = millis();
if(true == connect())
{
client->loop();
if(data != _data_sent)
{
if((MQTT_BUFFER_SIZE - 20) > data.length())
{
if( client->publish(topic.c_str(), data.c_str() , data.length()) )
{
_data_sent = data;
}
else
{
//Serial.printf("Sending data (topic: %s): FAILED!!!\n -> '%s'\n", topic.c_str(), data.c_str());
return(false);
}
}
else
{
//Serial.printf("Data length (%d) is larger than MQTT buffer(%d + 20bytes header)\n", data.length(), MQTT_BUFFER_SIZE);
return(false);
}
}
return(true);
}
}
return(false);
}

View file

@ -0,0 +1,237 @@
#include "oled.hpp"
//#include "main.hpp"
void Oled::begin()
{
display = new SSD1306Wire(0x3c, SDA, SCL);
Serial.println("Init OLED display ...");
display->init();
display->clear();
display->flipScreenVertically();
//display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_24);
display->setFont(ArialMT_Plain_16);
display->drawString(64, 2, "Init controller");
display->setFont(ArialMT_Plain_10);
display->drawString(64, 40, "You may hear some beeps.");
display->drawString(64, 52, "That's OK! ;-)");
display->display();
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_16);
}
void Oled::progressBar(uint8_t i)
{
display->drawProgressBar(6, 28, 116, 6, i);
display->display();
}
void Oled::next_page(bool speedchange)
{
static unsigned long last_switch_page_ms = 0;
if(last_switch_page_ms == 0)
{
page_nr = MIN_PAGE_NR;
last_switch_page_ms = millis();
}
if(speedchange == true)
{
last_switch_page_ms = millis();
page_nr = SPEED;
}
else{
if(millis() - last_switch_page_ms > PAGE_VIEW_TIME_MS)
{
last_switch_page_ms = millis();
if(page_nr >= MAX_PAGE_NR)
{
page_nr = MIN_PAGE_NR;
}
else
{
page_nr++;
}
}
}
page = (pages)page_nr;
}
void Oled::show_values(int speed, int min_speed, int max_speed, volatile DataStruct *HallData, uint8_t hall_sensors_count, unsigned long runtime, String ipaddr)
{
const uint8_t local_hall_count = 8;
static int _speed = 0;
static double _hall[local_hall_count] = {0, 0, 0, 0, 0, 0, 0, 0};
static unsigned long _runtime = 0;
static String _ipaddr = "-";
bool hall_has_changed = false;
for(uint8_t i = 0; i < min(local_hall_count,hall_sensors_count); i++)
{
if(_hall[i] != HallData[i].value)
{
hall_has_changed = true;
break;
}
}
if( _speed != speed || hall_has_changed == true || _runtime != runtime || _ipaddr != ipaddr)
{
next_page(_speed != speed);
_speed = speed;
for(uint8_t i = 0; i < min(local_hall_count,hall_sensors_count); i++)
{
_hall[i] = HallData[i].value;
}
_runtime = runtime; //runtime comes in in secs
_ipaddr = ipaddr;
show_page_header(ipaddr, page);
show_speed(speed, min_speed, max_speed, _hall[0], _runtime, page );
show_halls(HallData, min(local_hall_count,hall_sensors_count), page);
show_page_footer(page);
display->display();
}
}
void Oled::show_page_footer(pages page)
{
const int16_t distance = 1;
int16_t _xpos = 0;
uint8_t nr_pages = 1+(MAX_PAGE_NR - MIN_PAGE_NR);
const int16_t radius = 3;
const int16_t _ypos = 66 - radius;
uint8_t space_all_circles = nr_pages*(2*radius) + (nr_pages-1)*distance;
uint8_t start_xpos = (128-space_all_circles)/2;
for(uint8_t i = 0; i < nr_pages; i++)
{
_xpos = start_xpos + i*(radius*2+distance);
if((pages)i == page)
{
display->fillCircle(_xpos, _ypos, radius);
}
display->drawCircle(_xpos, _ypos, radius);
}
display->drawHorizontalLine(0,63,start_xpos-3);
display->drawHorizontalLine(_xpos+radius*2-2,63,128 - (_xpos+radius*2));
}
void Oled::show_page_header(String ipaddr, pages page)
{
xpos = 0;
ypos = 0;
display->clear();
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
switch(page)
{
case HALL1:
case HALL2:
display->drawString(0, ypos, "Measured numbers:");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
break;
case SPEED:
default:
if(ipaddr == "0.0.0.0")
{
display->drawString(0, ypos, "No WiFi.");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(128,ypos, "x");
}
else
{
display->drawString(0, ypos, "IP:" + ipaddr);
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(128,ypos, "Y");
display->drawString(124,ypos-2, "--");
}
break;
}
display->drawHorizontalLine(0,ypos+12, 128);
ypos = ypos + 13;
}
void Oled::show_speed(int speed, int min_speed, int max_speed, double u_min, unsigned long runtime, pages page)
{
if(page == SPEED)
{
static char _runtime_str[26];
static unsigned long _runtime = 0;
if( _runtime != runtime || _runtime == 0)
{
_runtime = runtime;
uint8_t _runtime_years = _runtime / (365*24*3600 + 6*3600); // this includes the leap year as an offset of 6hours each year -> all for years this is a full day
_runtime = _runtime - _runtime_years * (365*24*3600 + 6*3600);
uint8_t _runtime_month = _runtime / (30*24*3600); //assumes a month has 30 days ...
_runtime = _runtime - _runtime_month * (30*24*3600);
uint8_t _runtime_week = _runtime / (7*24*3600);
_runtime = _runtime - _runtime_week * (7*24*3600);
uint8_t _runtime_days = _runtime / (24*3600); // time in days
_runtime = _runtime - _runtime_days * (24*3600);
uint8_t _runtime_hour = _runtime / 3600 ;
_runtime = _runtime - _runtime_hour * 3600;
uint8_t _runtime_min = _runtime / 60;
_runtime = _runtime - _runtime_min * 60;
uint8_t _runtime_sec = _runtime;
sprintf(_runtime_str, "%01dy %02dm %01dw %01dd %02dh %02dm %02ds", _runtime_years, _runtime_month, _runtime_week, _runtime_days, _runtime_hour, _runtime_min, _runtime_sec);
}
uint8_t _ypos = ypos;
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
display->drawString(1, _ypos, "Speed:");
display->drawProgressBar(38, _ypos+4, 87, 5 , map(speed, min_speed, max_speed,0,100));
display->setFont(ArialMT_Plain_10);
_ypos=_ypos+9;
display->setFont(ArialMT_Plain_24);
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(83, _ypos, String(u_min));
display->setFont(ArialMT_Plain_16);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(85,_ypos+8, "U/min");
_ypos=_ypos+24;
display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64, _ypos, _runtime_str);
}
}
void Oled::show_halls(volatile DataStruct *HallData, uint8_t hall_sensor_count, pages page)
{
if(page == HALL1 || page == HALL2)
{
uint8_t hall_start = (page_nr-HALL1)*HALLS_PER_PAGE;
uint8_t hall_count = min(HALLS_PER_PAGE, (uint8_t)(hall_sensor_count-hall_start));
uint8_t _ypos = ypos;
uint8_t _xpos = 1;
display->setFont(ArialMT_Plain_10);
_ypos = _ypos + 1;
_xpos = _xpos + 1;
for(uint8_t i=hall_start; i<(hall_count+hall_start);i++)
{
String text = "H" + String(i+1) + " [" + String(HallData[i].unit) + "] ";
String value = String(HallData[i].value);
String point = ".";
uint16_t width_text = display->getStringWidth(text);
uint16_t width_value = display->getStringWidth(value);
uint16_t width_point = display->getStringWidth(point);
uint8_t nr_points = (128-_xpos-width_text-width_value)/width_point;
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(_xpos, _ypos, text);
for(uint8_t i=0;i<nr_points-1;i++)
{
display->drawString(_xpos+width_text+i*width_point, _ypos, point);
}
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(128,_ypos, value);
_ypos = _ypos + 11;
}
}
}