Browse Source

code cleanup

main
Hendrik Langer 7 years ago
parent
commit
d07842f4e3
  1. 42
      src/hardware.h
  2. 195
      src/main.cpp
  3. 2
      src/main.h
  4. 13
      src/mp3.cpp
  5. 2
      src/mp3.h
  6. 30
      src/screen.cpp
  7. 10
      src/screen.h

42
src/hardware.h

@ -0,0 +1,42 @@
#ifndef _HARDWARE_H
#define _HARDWARE_H
/* pin assignments */
static constexpr uint8_t buttonPin = 0;
static constexpr uint8_t sensorPin = 0;
static constexpr uint8_t rotaryPinA = 38;
static constexpr uint8_t rotaryPinB = 39;
static constexpr uint8_t rotaryPinButton = 22;
/* Wiring (Heltec OLED Lora)
* GND O O GND
* 5V O O 5V
* 3V3 O O 3V3
* GND O < 36 only input, no pullups
* RX * ? * 17
* TX * < 38 ROTARY_A only input, no pullups
* RST * BUTTON < 39 ROTARY_B only input, no pullups
* 0 * BUTTON < 34 only input, no pullups
* ROTARY_BTN 22 * < 35 only input, no pullups
* BME280_SDO 19 * LoRa_MISO ? * 32
* BME280_CS 23 * ? * 33
* 18 x LoRa_CS * 25 MAX98_DIN
* BME280_SCL/SCK 5 * LoRa_SCK LoRa_IRQ * 26
* 15 * OLED_SCL LoRa_MOSI * 27 BME280_SDA/SDI
* 2 * LoRa_RST * 14
* 4 * OLED_SDA * 12 MAX98_BCLK
* 17 * * 13 MAX98_LRC
* 16 * OLED_RST * 21
*/
/* Rotary Encoder
* 1 LED
* pinA A 2 LED
* GND C 3 BTN -|
* pinB B 4 LED /
* 5 Vin -|
*/
#endif /* _HARDWARE_H */

195
src/main.cpp

@ -3,36 +3,6 @@
#include <Arduino.h> #include <Arduino.h>
/* Wiring (Heltec OLED Lora)
* GND O O GND
* 5V O O 5V
* 3V3 O O 3V3
* GND O < 36 only input, no pullups
* RX * ? * 17
* TX * < 38 ROTARY_A only input, no pullups
* RST * BUTTON < 39 ROTARY_B only input, no pullups
* 0 * BUTTON < 34 only input, no pullups
* ROTARY_BTN 22 * < 35 only input, no pullups
* BME280_SDO 19 * LoRa_MISO ? * 32
* BME280_CS 23 * ? * 33
* 18 x LoRa_CS * 25 MAX98_DIN
* BME280_SCL/SCK 5 * LoRa_SCK LoRa_IRQ * 26
* 15 * OLED_SCL LoRa_MOSI * 27 BME280_SDA/SDI
* 2 * LoRa_RST * 14
* 4 * OLED_SDA * 12 MAX98_BCLK
* 17 * * 13 MAX98_LRC
* 16 * OLED_RST * 21
*/
/* Rotary Encoder
* 1 LED
* pinA A 2 LED
* GND C 3 BTN -|
* pinB B 4 LED /
* 5 Vin -|
*/
//Include Basecamp in this sketch //Include Basecamp in this sketch
#include <Basecamp.hpp> #include <Basecamp.hpp>
#include <Configuration.hpp> #include <Configuration.hpp>
@ -49,6 +19,7 @@
#include <NTPClient.h> #include <NTPClient.h>
#include "main.h" #include "main.h"
#include "hardware.h"
#include "mp3.h" #include "mp3.h"
#include "BME280.h" #include "BME280.h"
#include "rotary.h" #include "rotary.h"
@ -72,102 +43,50 @@ Screen* screen;
menuType menuChange = eNone; menuType menuChange = eNone;
uint32_t lastButtonPress = 0; uint32_t lastButtonPress = 0;
uint32_t lastUpdate = 0; uint32_t lastUpdate = 0;
uint32_t lastTransmit = 0;
//Variables for the sensor and the battery
static const int buttonPin = 0;
static const int ResetPin = 17;
static const int SensorPin = 0;
static const int BatteryPin = 34;
static const int rotaryPinA = 38;
static const int rotaryPinB = 39;
static const int rotaryPinButton = 22;
int sensorValue = 0;
//The batteryLimit defines the point at which the battery is considered empty.
int batteryLimit = 3300;
//This is used to control if the ESP should enter sleep mode or not
bool delaySleep = true;
//Variables for the mqtt packages and topics //Variables for the mqtt packages and topics
uint16_t statusPacketIdSub = 0; uint16_t statusPacketIdSub = 0;
String delaySleepTopic; String commandTopic;
String statusTopic; String temperatureTopic;
String batteryTopic; String humidityTopic;
String batteryValueTopic; String pressureTopic;
void setup() { void setup() {
// #include "soc/rtc_io_reg.h" // gpio configuration
// #include "soc/sens_reg.h"
//
// SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
// CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE | RTC_IO_X32N_RDE);
// CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, 1, RTC_IO_DAC_XTAL_32K_S);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, 3, RTC_IO_DRES_XTAL_32K_S);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, 0, RTC_IO_DBIAS_XTAL_32K_S);
// SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
// REG_SET_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M);
// REG_CLR_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RDE_M | RTC_IO_PDAC1_RUE_M);
// REG_SET_FIELD(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_FUN_SEL, 1);
// REG_SET_FIELD(SENS_SAR_DAC_CTRL1_REG, SENS_DEBUG_BIT_SEL, 0);
// const uint8_t sel = 4; /* sel = 4 : 32k XTAL; sel = 5 : internal 150k RC */
// REG_SET_FIELD(RTC_IO_RTC_DEBUG_SEL_REG, RTC_IO_DEBUG_SEL0, sel);
//
//configuration of the battery and sensor pins
// pinMode(ResetPin, INPUT_PULLDOWN);
// pinMode(SensorPin, INPUT_PULLDOWN);
// pinMode(BatteryPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP); pinMode(buttonPin, INPUT_PULLUP);
pinMode(18, OUTPUT); pinMode(18, OUTPUT);
digitalWrite(18, HIGH); // disable LoRa_CS digitalWrite(18, HIGH); // disable LoRa_CS
//read the status of the doorsensor as soon as possible to determine the state that triggered it
// sensorValue = digitalRead(SensorPin);
//Initialize Basecamp //Initialize Basecamp
iot.begin(); iot.begin();
u8g2.begin();
// delay(50);
screen = new WelcomeScreen();
screen->draw();
menuChange = eMainScreen;
u8g2.setContrast(127);
bme280.begin(); bme280.begin();
for (int i=0; i<5; i++) {
delay(500);
bme280.printValues(); bme280.printValues();
}
u8g2.begin();
delay(50);
screen = new MainScreen();
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(2,10,"esp32-node by hendrik"); // write something to the internal memory
if (iot.configuration.get("WifiConfigured") != "True") {
u8g2.drawStr(2,30,"NOT CONFIGURED!");
u8g2.drawStr(12,40,"SSID: \"ESP32\"");
u8g2.drawStr(12,55,"http://192.168.4.1");
} else {
u8g2.drawStr(2,30,"Welcome!");
u8g2.drawStr(12,40,"connecting..");
}
u8g2.drawFrame(0,0,u8g2.getDisplayWidth(),u8g2.getDisplayHeight() );
u8g2.sendBuffer(); // transfer internal memory to the display
//Configure the MQTT topics //Configure the MQTT topics
delaySleepTopic = "esp32-node/cmd/" + iot.hostname + "/delaysleep"; commandTopic = "esp32-node/cmd/" + iot.hostname + "/command";
statusTopic = "esp32-node/stat/" + iot.hostname + "/status"; temperatureTopic = "esp32-node/stat/" + iot.hostname + "/temperature";
batteryTopic = "esp32-node/stat/" + iot.hostname + "/battery"; humidityTopic = "esp32-node/stat/" + iot.hostname + "/humidity";
batteryValueTopic = "esp32-node/stat/" + iot.hostname + "/batteryvalue"; pressureTopic = "esp32-node/stat/" + iot.hostname + "/pressure";
//Set up the Callbacks for the MQTT instance. Refer to the Async MQTT Client documentation //Set up the Callbacks for the MQTT instance. Refer to the Async MQTT Client documentation
// TODO: We should do this actually _before_ connecting the mqtt client... // TODO: We should do this actually _before_ connecting the mqtt client...
iot.mqtt.onConnect(onMqttConnect); iot.mqtt.onConnect(onMqttConnect);
iot.mqtt.onPublish(suspendESP); //iot.mqtt.onPublish(NULL);
iot.mqtt.onMessage(onMqttMessage); iot.mqtt.onMessage(onMqttMessage);
while (iot.wifi.status() != WL_CONNECTED) { while (iot.wifi.status() != WL_CONNECTED) {
delay(500); delay(500);
Serial.print("."); Serial.print(".");
screen->draw();
} }
IPAddress localIP = iot.wifi.getIP(); IPAddress localIP = iot.wifi.getIP();
@ -176,18 +95,9 @@ void setup() {
timeClient.begin(); timeClient.begin();
timeClient.update(); timeClient.update();
timeClient.getFormattedTime().toCharArray(timeStr, 50);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
// u8g2.setDrawColor(2);
u8g2.drawStr(30, 30, timeStr);
u8g2.drawStr(30, 50, ipStr);
u8g2.sendBuffer();
mp3.begin(); mp3.begin();
u8g2.setContrast(127);
rotary.registerCallback(rotation); rotary.registerCallback(rotation);
rotary.begin(rotaryPinA, rotaryPinB, rotaryPinButton); rotary.begin(rotaryPinA, rotaryPinB, rotaryPinButton);
} }
@ -198,78 +108,40 @@ void onMqttConnect(bool sessionPresent) {
DEBUG_PRINTLN(__func__); DEBUG_PRINTLN(__func__);
//Subscribe to the delay topic //Subscribe to the delay topic
iot.mqtt.subscribe(delaySleepTopic.c_str(), 0); iot.mqtt.subscribe(commandTopic.c_str(), 0);
//Trigger the transmission of the current state. //Trigger the transmission of the current state.
transmitStatus(); transmitStatus();
lastTransmit = millis();
} }
//This function transfers the state of the sensor. That includes the door status, battery status and level
void transmitStatus() { void transmitStatus() {
DEBUG_PRINTLN(__func__); DEBUG_PRINTLN(__func__);
if (sensorValue == 0) {
DEBUG_PRINTLN("Door open");
//Transfer the current state of the sensor to the MQTT broker
statusPacketIdSub = iot.mqtt.publish(statusTopic.c_str(), 1, true, "open" );
//Configure the wakeup pin to wake if the door is closed
esp_sleep_enable_ext0_wakeup((gpio_num_t)SensorPin, 1);
} else {
DEBUG_PRINTLN("Door closed");
//Transfer the current state of the sensor to the MQTT broker
statusPacketIdSub = iot.mqtt.publish(statusTopic.c_str(), 1, true, "closed" );
//Configure the wakeup pin to wake if the door is closed
esp_sleep_enable_ext0_wakeup((gpio_num_t)SensorPin, 0);
}
//Read the current analog battery value
// sensorValue = analogRead(BatteryPin);
//sensorC stores the battery value as a char
char sensorC[6]; char sensorC[6];
//convert the sensor value to a string sprintf(sensorC, "%04i", bme280.readTemperature());
sprintf(sensorC, "%04i", sensorValue); statusPacketIdSub = iot.mqtt.publish(temperatureTopic.c_str(), 1, true, sensorC);
//Send the sensor value to the MQTT broker sprintf(sensorC, "%04i", bme280.readHumidity());
iot.mqtt.publish(batteryValueTopic.c_str(), 1, true, sensorC); statusPacketIdSub = iot.mqtt.publish(humidityTopic.c_str(), 1, true, sensorC);
//Check the battery level and publish the state sprintf(sensorC, "%04i", bme280.readPressure());
if (sensorValue < batteryLimit) { statusPacketIdSub = iot.mqtt.publish(pressureTopic.c_str(), 1, true, sensorC);
DEBUG_PRINTLN("Battery empty");
iot.mqtt.publish(batteryTopic.c_str(), 1, true, "empty" );
} else {
DEBUG_PRINTLN("Battery full");
iot.mqtt.publish(batteryTopic.c_str(), 1, true, "full" );
}
DEBUG_PRINTLN("Data published");
} }
//This topic is called if an MQTT message is received //This topic is called if an MQTT message is received
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
DEBUG_PRINTLN(__func__); DEBUG_PRINTLN(__func__);
//Check if the payload eqals "true" and set delaySleep correspondigly
//Since we only subscribed to one topic, we only have to compare the payload //Since we only subscribed to one topic, we only have to compare the payload
if (strcmp(payload, "true") == 0) { if (strcmp(payload, "true") == 0) {
delaySleep = true;
} else {
delaySleep = false;
} }
} }
void suspendESP(uint16_t packetId) { void suspend() {
DEBUG_PRINTLN(__func__);
//Check if the published package is the one of the door sensor
if (packetId == statusPacketIdSub) {
if (delaySleep == true) {
DEBUG_PRINTLN("Delaying Sleep");
return;
}
DEBUG_PRINTLN("Entering deep sleep"); DEBUG_PRINTLN("Entering deep sleep");
esp_sleep_enable_ext0_wakeup((gpio_num_t)sensorPin, 0);
//properly disconnect from the MQTT broker //properly disconnect from the MQTT broker
iot.mqtt.disconnect(); iot.mqtt.disconnect();
//send the ESP into deep sleep //send the ESP into deep sleep
esp_deep_sleep_start(); esp_deep_sleep_start();
}
} }
@ -293,6 +165,11 @@ void loop()
sprintf(weatherStr, "%.1f°C %.1f%% %.0fhPa", bme280.readTemperature(), bme280.readHumidity(), bme280.readPressure()); sprintf(weatherStr, "%.1f°C %.1f%% %.0fhPa", bme280.readTemperature(), bme280.readHumidity(), bme280.readPressure());
} }
if(millis() - lastTransmit >= 60000) {
lastTransmit = millis();
transmitStatus();
}
if (menuChange != eNone) { if (menuChange != eNone) {
delete screen; delete screen;
if (menuChange == eMainScreen) screen = new MainScreen(); if (menuChange == eMainScreen) screen = new MainScreen();

2
src/main.h

@ -5,6 +5,6 @@ void setup();
void onMqttConnect(bool sessionPresent); void onMqttConnect(bool sessionPresent);
void transmitStatus(); void transmitStatus();
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total); void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
void suspendESP(uint16_t packetId); void suspend();
void loop(); void loop();
void rotation(int i, int direction, int buttonPressed); void rotation(int i, int direction, int buttonPressed);

13
src/mp3.cpp

@ -41,7 +41,7 @@ void MP3::cTaskWrapper(void* parameters) {
void MP3::stop() { void MP3::stop() {
Serial.println("Stopping mp3 playback"); Serial.println("Stopping mp3 playback");
strcpy(titleStr, ""); strcpy(titleStr, "stopping..");
playing = false; playing = false;
// while (audioTaskHandle && eTaskGetState(audioTaskHandle) != eDeleted) { // while (audioTaskHandle && eTaskGetState(audioTaskHandle) != eDeleted) {
// Serial.println("waiting for audio to finish"); // Serial.println("waiting for audio to finish");
@ -86,7 +86,7 @@ void MP3::mp3_decoder_task(void *pvParameters) {
AudioOutputI2S *out = nullptr; AudioOutputI2S *out = nullptr;
strcpy(titleStr, "..."); strcpy(titleStr, "loading...");
file = new AudioFileSourceICYStream(URL); file = new AudioFileSourceICYStream(URL);
file->RegisterMetadataCB(MDCallback, (void*)"ICY"); file->RegisterMetadataCB(MDCallback, (void*)"ICY");
buff = new AudioFileSourceBuffer(file, preallocateBuffer, preallocateBufferSize); buff = new AudioFileSourceBuffer(file, preallocateBuffer, preallocateBufferSize);
@ -107,11 +107,6 @@ void MP3::mp3_decoder_task(void *pvParameters) {
playing = true; playing = true;
while(decoder->isRunning()) { while(decoder->isRunning()) {
if (millis()-lastms > 1000) {
lastms = millis();
Serial.printf("Running for %d ms...\n", lastms);
Serial.flush();
}
if (volumeChanged) { if (volumeChanged) {
volumeChanged = false; volumeChanged = false;
out->SetGain(((float)volume)/100.0); out->SetGain(((float)volume)/100.0);
@ -122,7 +117,7 @@ void MP3::mp3_decoder_task(void *pvParameters) {
} }
Serial.printf("MP3 done\n"); Serial.printf("MP3 done\n");
strcpy(titleStr, "___"); strcpy(titleStr, "stopped");
playing = false; playing = false;
@ -147,7 +142,7 @@ void MP3::mp3_decoder_task(void *pvParameters) {
} }
bool MP3::begin() { bool MP3::begin() {
strcpy(titleStr, ">"); strcpy(titleStr, "ready");
// First, preallocate all the memory needed for the buffering and codecs, never to be freed // First, preallocate all the memory needed for the buffering and codecs, never to be freed
preallocateBuffer = malloc(preallocateBufferSize); preallocateBuffer = malloc(preallocateBufferSize);

2
src/mp3.h

@ -33,8 +33,6 @@ class MP3 {
static constexpr int preallocateCodecSize = 29192; // MP3 codec max mem needed static constexpr int preallocateCodecSize = 29192; // MP3 codec max mem needed
void *preallocateBuffer = NULL; void *preallocateBuffer = NULL;
void *preallocateCodec = NULL; void *preallocateCodec = NULL;
int lastms = 0;
}; };
#endif /* _MP3_H */ #endif /* _MP3_H */

30
src/screen.cpp

@ -56,12 +56,13 @@ uint8_t SelectionList::select() {
} }
MainMenu::MainMenu() { MainMenu::MainMenu() {
title = "Main Menu";
string_list = { string_list = {
"PLAY", "PLAY",
"Radio Stations", "Radio Stations",
"test", "test",
"test3", "test3",
"« Return"}; "\xAB Return"};
if (mp3.playing) { if (mp3.playing) {
string_list[0] = "STOP"; string_list[0] = "STOP";
} }
@ -99,6 +100,7 @@ uint8_t MainMenu::select() {
} }
StationMenu::StationMenu() { StationMenu::StationMenu() {
title = "Radio Stations";
string_list = { string_list = {
"80s Planet", "80s Planet",
"Left Coast 70s", "Left Coast 70s",
@ -110,7 +112,7 @@ StationMenu::StationMenu() {
"Live Ireland", "Live Ireland",
"Ye Ol Celtic Pub", "Ye Ol Celtic Pub",
"Gone Country - NZCMR", "Gone Country - NZCMR",
"« Return"}; "\xAB Return"};
} }
uint8_t StationMenu::select() { uint8_t StationMenu::select() {
@ -161,6 +163,27 @@ namespace { /* anonymous namespace for helper functions */
} }
void WelcomeScreen::draw() {
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(2,10,"esp32-node by hendrik"); // write something to the internal memory
if (iot.configuration.get("WifiConfigured") != "True") {
u8g2.drawStr(2,30,"NOT CONFIGURED!");
u8g2.drawStr(12,40,"SSID: \"ESP32\"");
u8g2.drawStr(12,55,"http://192.168.4.1");
} else {
u8g2.drawStr(2,30,"Welcome!");
u8g2.drawStr(12,40,"WiFi connecting");
u8g2.setCursor(80, 40);
progress++;
for (int i = 0; i<progress; i++) {
u8g2.print(".");
}
}
u8g2.drawFrame(0,0,u8g2.getDisplayWidth(),u8g2.getDisplayHeight() );
u8g2.sendBuffer(); // transfer internal memory to the display
}
void MainScreen::draw() { void MainScreen::draw() {
u8g2.clearBuffer(); // clear the internal memory u8g2.clearBuffer(); // clear the internal memory
@ -181,8 +204,9 @@ void MainScreen::draw() {
u8g2.setFontMode(0); u8g2.setFontMode(0);
u8g2.setDrawColor(1); u8g2.setDrawColor(1);
} else { } else {
u8g2.setFont(u8g2_font_inb19_mf); u8g2.setFont(u8g2_font_inb19_mf);
u8g2.setFontMode(0);
u8g2.setDrawColor(1);
u8g2.drawStr(0, 20, timeStr); u8g2.drawStr(0, 20, timeStr);
u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font
u8g2.drawUTF8(0, 30, weatherStr); u8g2.drawUTF8(0, 30, weatherStr);

10
src/screen.h

@ -20,7 +20,7 @@
#include "BME280.h" #include "BME280.h"
#include "image.h" #include "image.h"
enum menuType { eNone=0, eMainScreen, eMainMenu, eStationMenu }; enum menuType { eNone=0, eWelcomeScreen, eMainScreen, eMainMenu, eStationMenu };
extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;
extern char timeStr[]; extern char timeStr[];
@ -81,6 +81,14 @@ class MainScreen : public Screen {
uint8_t volume = 20; uint8_t volume = 20;
}; };
class WelcomeScreen : public Screen {
public:
void draw(void) override;
const char* title = "Welcome Screen";
private:
int progress = 0;
};
class MainMenu : public SelectionList { class MainMenu : public SelectionList {
public: public:
MainMenu(); MainMenu();

Loading…
Cancel
Save