Compare commits

...

10 Commits

Author SHA1 Message Date
Daan Meijer
5d46b187ca more impactful brightness changes 2025-02-09 20:40:30 +01:00
Daan Meijer
9178984696 more impactful brightness changes 2025-02-09 20:39:52 +01:00
Daan Meijer
aded5832ea start with object oriented approach 2025-01-25 00:26:36 +01:00
Daan Meijer
bf6c241c04 mqtt works 2025-01-24 23:27:10 +01:00
Daan Meijer
b4f71f60fa wifi working async 2025-01-24 22:53:18 +01:00
Daan Meijer
ef73f2c7ac added skip led 2025-01-24 22:42:22 +01:00
Daan Meijer
347241bee2 first completely working version, no wifi 2025-01-24 22:36:10 +01:00
Daan Meijer
31c9c740b3 controls work, rendering on low brightness is wonky 2025-01-22 23:38:06 +01:00
Daan Meijer
59a5fd0770 starting async implementation 2025-01-22 22:02:06 +01:00
Daan Meijer
d6057525f7 wifi working 2025-01-15 23:09:57 +01:00
11 changed files with 525 additions and 280 deletions

View File

@ -29,6 +29,7 @@ lib_deps =
devyte/ESPAsyncDNSServer@^1.0.0
me-no-dev/ESPAsyncUDP
makuna/NeoPixelBus @ ^2.8.0
knolleary/PubSubClient@^2.8
lib_ldf_mode = chain+
monitor_filters =
default
@ -37,22 +38,10 @@ board_build.filesystem = littlefs
board_build.f_cpu = 80000000L
[env:esp32c3_supermini]
; platform = espressif32
; board = esp32-c3-devkitm-1
; platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF5
; board = lolin_c3_mini
board = dfrobot_beetle_esp32c3
platform = espressif32
framework = arduino
monitor_speed = 460800
lib_deps =
fastled/FastLED@^3.7.0
; [env:dfrobot_beetle_esp32c3]
; platform = espressif32
; board = dfrobot_beetle_esp32c3
; framework = arduino
; lib_deps =
; fastled/FastLED@^3.7.0
knolleary/PubSubClient@^2.8

140
src/Controls.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "Controls.h"
uint8_t controlPins[] = {
PIN_A,
PIN_B,
PIN_KEY,
};
uint16_t prevState[3];
auto lastChange = micros();
uint8_t pinChanges[128];
uint8_t pinChangeIndex = 0;
void Controls_direction_reset(){
lastChange = 0;
pinChangeIndex = 0;
}
auto lastKey = micros();
ControlsCallback handler = NULL;
void Controls_handler(ControlsCallback newHandler){
handler = newHandler;
}
void Controls_send_event(ControlEvent event){
if(handler){
handler(event);
}
}
void Controls_loop(void *pvParameters){
lastKey = 0;
lastChange = 0;
while(true){
for(uint8_t a=0; a<sizeof(controlPins); a++){
auto pin = controlPins[a];
auto currentValueAnalog = analogRead(pin);
auto currentValue = currentValueAnalog > 3072;
auto prevValue = prevState[a];
if(CONTROLS_DEBUG){
Serial.printf("Pin %d: %d->%d (%d)\n", pin, prevValue, currentValue, currentValueAnalog);
}
// if(abs(currentValue - prevValue) > 100){
if(currentValue != prevValue){
if(pin == PIN_KEY){
if(currentValue){
auto duration = micros() - lastKey;
if(duration > KEY_DURATION_MS * 1000){
if(CONTROLS_DEBUG){
Serial.printf("Key: %d\n", duration);
}
Controls_send_event(Key);
}else{
if(CONTROLS_DEBUG){
Serial.println("Too short");
}
}
lastKey = 0;
} else {
lastKey = micros();
}
}else{
pinChanges[pinChangeIndex++] = pin;
lastChange = micros();
}
}
prevState[a] = currentValue;
}
//maybe we have a valid sequence
if(pinChangeIndex >= 4){
// Serial.printf("Have %d changes\n", pinChangeIndex);
for(uint8_t base = 0; base + 4 <= pinChangeIndex; base += 4){
if(
pinChanges[base + 0] == PIN_A &&
pinChanges[base + 1] == PIN_B &&
pinChanges[base + 2] == PIN_A &&
pinChanges[base + 3] == PIN_B
){
if(CONTROLS_DEBUG){
Serial.println("Dir A");
}
Controls_send_event(Counterclockwise);
}else if(
pinChanges[base + 0] == PIN_B &&
pinChanges[base + 1] == PIN_A &&
pinChanges[base + 2] == PIN_B &&
pinChanges[base + 3] == PIN_A
){
if(CONTROLS_DEBUG){
Serial.println("Dir B");
}
Controls_send_event(Clockwise);
}else{
if(CONTROLS_DEBUG){
Serial.println("Unknown direction");
}
}
}
Controls_direction_reset();
}
if(lastChange){
if(micros() - lastChange > 100 * 1000){
if(CONTROLS_DEBUG){
Serial.println("changes expired");
}
Controls_direction_reset();
}
}
vTaskDelay(1/portTICK_PERIOD_MS);
}
}
void Controls_setup(){
pinMode(PIN_A, INPUT_PULLDOWN);
pinMode(PIN_B, INPUT_PULLDOWN);
pinMode(PIN_KEY, INPUT_PULLDOWN);
TaskHandle_t taskControls = NULL;
xTaskCreate(Controls_loop, "Controls_loop", 1000, NULL, tskIDLE_PRIORITY, &taskControls);
}

23
src/Controls.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <Arduino.h>
#define PIN_A 2
#define PIN_B 3
#define PIN_KEY 4
#define KEY_DURATION_MS 120
#define CONTROLS_DEBUG false
enum ControlEvent {
Clockwise,
Counterclockwise,
Key
};
typedef void (* ControlsCallback)( ControlEvent ) ;
void Controls_setup();
void Controls_handler(ControlsCallback callback);

View File

@ -1,234 +1,76 @@
#define INCLUDE_LED
#ifdef INCLUDE_LED
#include "Led.h"
#endif
#include <Arduino.h>
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between runs if no callback methods were invoked during the pass
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
// #define ENABLE_MQTT
// #define ENABLE_WIFI
// #define ENABLE_FS
// #define ENABLE_PINFINDER
// #include <TaskScheduler.h>
#ifdef ENABLE_MQTT
#include "MQTT.h"
#endif
#ifdef ENABLE_WIFI
#include "Wifi.h"
#endif
#ifdef ENABLE_FS
#include "FS.h"
#include <LittleFS.h>
#endif
#ifdef ENABLE_PINFINDER
#include "PinFinder.h"
#endif
#include "Hanglamp.hpp"
void feedWatchdog(){
// ESP.wdtFeed();
}
bool blinkStatus = false;
void blink(){
blinkStatus = !blinkStatus;
digitalWrite(LED_BUILTIN, blinkStatus);
}
#ifdef INCLUDE_LED
CRGB colorTable[] = {
CRGB(255, 243, 218),
CRGB(255, 250, 237),
CRGB(255, 255, 255),
CRGB(250, 233, 213),
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow,
};
uint8_t colorIndex = 0;
void colors(){
colorIndex++;
Hanglamp::Hanglamp(){
}
void Hanglamp::setup(){
}
void Hanglamp::setColor(CRGB color){
jumpTo(color);
}
void Hanglamp::nextColor(){
this->colorIndex++;
if(colorIndex >= (sizeof(colorTable) / sizeof(CRGB))){
colorIndex = 0;
}
Serial.printf("colorIndex: %d\n", colorIndex);
jumpTo(colorTable[colorIndex]);
Serial.printf("colorIndex: %d\n", this->colorIndex);
setColor(colorTable[this->colorIndex]);
}
#endif
void setup() {
void Hanglamp::setBrightness(int brightness){
uint8_t newBrightness =
brightness < 0 ? 0 :
brightness > 255 ? 255 :
brightness;
this->brightness = newBrightness;
Serial.printf("new brightness: %d\n", newBrightness);
FastLED.setBrightness(newBrightness);
FastLED.show();
#ifdef ENABLE_MQTT
MQTT_publish("hanglamp/brightness", String(newBrightness));
#endif
}
void Hanglamp::adjustBrightness(int add){
this->setBrightness(this->brightness + add);
}
Serial.begin(115200);
delay(500);
#ifdef ENABLE_FS
if(!LittleFS.begin()){
Serial.println("LittleFS Mount Failed");
return;
void Hanglamp::controlsCallback(ControlEvent event){
Serial.printf("ControlEvent: %d\n", event);
switch(event){
case Clockwise:
adjustBrightness(4);
break;
case Counterclockwise:
adjustBrightness(-4);
break;
case Key:
nextColor();
break;
}
#endif
// runner.init();
Serial.println("Initialized scheduler");
Serial.println("Scheduled tasks");
#ifdef ENABLE_PINFINDER
PinFinder_setup();
#endif
#ifdef INCLUDE_LED
Led_setup();
jumpTo(CRGB(0xFF00FF));
#endif
#ifdef ENABLE_WIFI
Wifi_setup();
#endif
#ifdef INCLUDE_LED
jumpTo(CRGB(0x00FFFF));
jumpTo(CRGB(0x000000));
#endif
#ifdef ENABLE_MQTT
MQTT_setup();
#endif
#ifdef ENABLE_OTA
OTA_setup();
#endif
#ifdef INCLUDE_LED
jumpTo(CRGB(0x00FFFF));
#endif
// ESP.wdtEnable(10000);
}
void loop() {
#ifdef ENABLE_MQTT
MQTT_loop();
#endif
#ifdef ENABLE_OTA
OTA_loop();
#endif
#ifdef ENABLE_PINFINDER
PinFinder_loop();
#endif
#ifdef INCLUDE_LED
colors();
#endif
delay(1000);
return;
sleep(2000);
// Led_loop();
String command;
while(Serial.available()) {
command = Serial.readString();// read the incoming data as string
Serial.print("Have command: ");
Serial.println(command);
int index = command.indexOf(":");
if(index >= 0){
String name = command.substring(0, index);
Serial.print("Have command name: ");
Serial.println(name);
#ifdef INCLUDE_LED
if(name.equals("c")){
//c:0xff4000
//c:0xff0000
//c:0x00ff00
//c:0x0000ff
String color = command.substring(index+1);
if(color.startsWith("0x")){
color = color.substring(2);
}
int value = strtol(color.c_str(), NULL, 16);
CRGB target;
target.r = (value >> 16) & 0xFF;
target.g = (value >> 8) & 0xFF;
target.b = (value >> 0) & 0xFF;
jumpTo(target);
}
#endif
}
}
void Hanglamp::status(CRGB color){
Led_status(color);
}

24
src/Hanglamp.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <FastLED.h>
#include "Led.h"
#include "Controls.h"
class Hanglamp {
public:
Hanglamp();
void setup();
void setBrightness(int brightness);
void adjustBrightness(int add);
void nextColor();
void controlsCallback(ControlEvent event);
void status(CRGB color);
void setColor(CRGB color);
private:
char colorIndex = 0;
int brightness = 128;
};

View File

@ -5,16 +5,23 @@ CRGB led;
CRGB source;
CRGB target;
#ifdef LEVEL_SHIFT_WS2812B
#define SKIP_PIXELS 1
#else
#define SKIP_PIXELS 0
#endif
CRGB strip1[STRIP_LENGTH];
CRGB strip2[STRIP_LENGTH];
#define NUM_LEDS STRIP_LENGTH + SKIP_PIXELS
// Add one black pixel to the front
CRGB strip1[NUM_LEDS];
CRGB strip2[NUM_LEDS];
int fadeStart = 0;
#ifdef LED_NEOPIXEL_BUS
NeoPixelBus<NeoGrbFeature, NeoWs2812xMethod> strip(STRIP_LENGTH, PIN_STRIP1);
#endif
void fadeTo(const CRGB & dest){
@ -40,10 +47,10 @@ void fadeTo(const CRGB & dest){
void displayLed(){
#ifdef LED_FASTLED
for(uint8_t index = 0; index < STRIP_LENGTH; index++){
for(uint8_t index = SKIP_PIXELS; index < NUM_LEDS; index++){
// Serial.printf("Led 1:%02d 0x%02x%02x%02x\n", index, strip1[index].r, strip1[index].g, strip1[index].b);
}
for(uint8_t index = 0; index < STRIP_LENGTH; index++){
for(uint8_t index = SKIP_PIXELS; index < NUM_LEDS; index++){
// Serial.printf("Led 2:%02d 0x%02x%02x%02x\n", index, strip2[index].r, strip2[index].g, strip2[index].b);
}
auto before = micros();
@ -73,7 +80,7 @@ void jumpTo(const CRGB & dest){
// Serial.printf("FastLED.showColor took %d micros\n", after - before);
// return;
for(uint8_t index = 0; index < STRIP_LENGTH; index++){
for(uint8_t index = SKIP_PIXELS; index < NUM_LEDS; index++){
strip1[index] = CRGB(dest);
strip2[index] = CRGB(dest);
}
@ -116,8 +123,10 @@ void Led_setup(){
// analogWriteRange(255);
#ifdef LED_FASTLED
FastLED.addLeds<WS2812B, PIN_STRIP1>(strip2, STRIP_LENGTH);
FastLED.addLeds<WS2812B, PIN_STRIP2>(strip2, STRIP_LENGTH);
FastLED.addLeds<WS2812B, PIN_STRIP1, GRB>(strip2, NUM_LEDS);
FastLED.addLeds<WS2812B, PIN_STRIP2, GRB>(strip2, NUM_LEDS);
strip1[0] = CRGB::Black;
strip2[0] = CRGB::Black;
#endif
#ifdef LED_NEOPIXEL_BUS
@ -148,3 +157,9 @@ void Led_loop(){
FastLED.show();
delay(500);
}
void Led_status(CRGB color){
strip1[0] = color;
strip2[0] = color;
FastLED.show();
}

View File

@ -20,10 +20,11 @@
#include <NeoPixelBus.h>
#endif
#define PIN_STRIP1 3
#define PIN_STRIP2 4
#define PIN_STRIP1 5
#define PIN_STRIP2 6
#define STRIP_LENGTH 46
#define LEVEL_SHIFT_WS2812B
#define FADE_PERIOD 3.0f
@ -35,3 +36,5 @@ void jumpTo(const CRGB & dest);
void fadeTo(const CRGB & dest);
void fadeTask();
void Led_status(CRGB color);

View File

@ -1,13 +1,9 @@
#ifdef ENABLE_MQTT
#include "MQTT.h"
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
WiFiClient espClient;
PubSubClient client(espClient);
@ -17,12 +13,23 @@ std::vector<SubscribedChannel> * channels = new std::vector<SubscribedChannel>()
char mqtt_server[40] = "manus";
char mqtt_port[6] = "1883";
uint32_t chipId = 0;
void connect() {
Serial.print("Attempting MQTT connection...");
if (WiFi.status() != WL_CONNECTED){
Serial.println("Wifi not connected");
return;
}
Serial.println("Attempting MQTT connection...");
// Create a random client ID
String clientId = "Konijntje-";
clientId += String(ESP.getChipId());
String clientId = "Hanglamp-";
clientId += String(chipId, 16);
Serial.printf("MQTT: Connecting as %s\n", clientId.c_str());
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
@ -81,7 +88,11 @@ void MQTT_callback(char* topic, uint8_t * payload, unsigned int length){
void MQTT_setup(){
Serial.println("MQTT_init");
for (int i = 0; i < 17; i = i + 8) {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
Serial.printf("MQTT_init: %06x\n", chipId);
client.setServer(mqtt_server, String(mqtt_port).toInt());
client.setCallback(MQTT_callback);
@ -91,29 +102,32 @@ void MQTT_setup(){
// sprintf(buff, "%08x", _pCallback);
// Serial.println(buff);
connect();
TaskHandle_t taskMqtt = NULL;
xTaskCreate(MQTT_loop, "Wifi_loop", 10000, NULL, tskIDLE_PRIORITY, &taskMqtt);
}
void MQTT_loop(){
void MQTT_loop(void* params){
#if DEBUG_GENERAL
Serial.println("MQTT_loop()");
#endif
int reconnectCounter = 0;
while(!client.connected() && reconnectCounter < 3) {
Serial.println("MQTT: connecting...");
reconnectCounter++;
connect();
while(true){
#if DEBUG_GENERAL
Serial.println("MQTT_loop()");
#endif
int reconnectCounter = 0;
while(!client.connected() && reconnectCounter < 3) {
Serial.println("MQTT: connecting...");
reconnectCounter++;
connect();
if(client.connected()){
Serial.println("MQTT: succes!");
break;
}else{
Serial.println("MQTT: connection failed, try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
if(client.connected()){
Serial.println("MQTT: succes!");
break;
}else{
Serial.println("MQTT: connection failed, try again in 5 seconds");
// Wait 5 seconds before retrying
vTaskDelay(5000/portTICK_PERIOD_MS);
}
}
client.loop();
vTaskDelay(100/portTICK_PERIOD_MS);
}
client.loop();
}
#endif

View File

@ -3,6 +3,8 @@
#include "Arduino.h"
#include <WiFi.h>
using namespace std;
@ -17,5 +19,5 @@ struct SubscribedChannel {
void MQTT_publish(const char * topic, String str);
void MQTT_publish(const char * topic, const char * msg);
void MQTT_loop();
void MQTT_loop(void* params);
void MQTT_setup();

View File

@ -1,10 +1,6 @@
#ifdef ENABLE_WIFI
#include <ESP8266WiFi.h>
#include <ESPAsync_WiFiManager.h>
#include <Arduino.h>
#include <WiFi.h>
#include "WifiSettings.h"
@ -24,15 +20,18 @@ void Wifi_setup_softap(){
}
void Wifi_setup(){
void Wifi_loop(void* params){
Serial.println("Wifi_setup()");
WiFi.mode(WIFI_STA);
//TODO:
WiFi.begin(WIFI_ESSID, WIFI_PASSWORD);
WiFi.mode(WIFI_STA);
//TODO:
WiFi.begin(WIFI_ESSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
while (true)
{
while (WiFi.status() != WL_CONNECTED)
{
vTaskDelay(500 / portTICK_PERIOD_MS);
Serial.println("Wifi waiting...");
}
Serial.println("");
@ -40,6 +39,13 @@ void Wifi_setup(){
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
vTaskDelay(60*1000 / portTICK_PERIOD_MS);
}
}
#endif
void Wifi_setup(){
TaskHandle_t taskWifi = NULL;
xTaskCreate(Wifi_loop, "Wifi_loop", 10000, NULL, tskIDLE_PRIORITY, &taskWifi);
}

187
src/main.cpp Normal file
View File

@ -0,0 +1,187 @@
#define INCLUDE_LED
#ifdef INCLUDE_LED
#include "Led.h"
#endif
#include <Arduino.h>
#define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between runs if no callback methods were invoked during the pass
#define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
#define ENABLE_MQTT
#define ENABLE_WIFI
// #define ENABLE_FS
// #define ENABLE_PINFINDER
#define ENABLE_COLORS
// #define ENABLE_PIN_SENSING
#define ENABLE_CONTROLS
#ifdef ENABLE_WIFI
#include "Wifi.h"
#endif
#ifdef ENABLE_MQTT
#include "MQTT.h"
#endif
#ifdef ENABLE_FS
#include "FS.h"
#include <LittleFS.h>
#endif
#ifdef ENABLE_PINFINDER
#include "PinFinder.h"
#endif
#ifdef ENABLE_CONTROLS
#include "Controls.h"
#endif
#include "Hanglamp.hpp"
Hanglamp hanglamp;
#ifdef ENABLE_CONTROLS
void controlsCallback(ControlEvent event){
hanglamp.controlsCallback(event);
}
#endif
#ifdef ENABLE_LED
#endif
void setup() {
Serial.begin(115200);
Serial.println("Waiting...");
delay(1500);
Serial.println("That's long enough.");
#ifdef ENABLE_PIN_SENSING
for(int i=0; i<sizeof(sensePins)/sizeof(gpio_num_t); i++){
auto pin = sensePins[i];
Serial.printf("Setting pin %d to input\n", pin);
// gpio_reset_pin(pin);
pinMode(pin, INPUT);
}
#endif
#ifdef ENABLE_FS
if(!LittleFS.begin()){
Serial.println("LittleFS Mount Failed");
return;
}
#endif
#ifdef ENABLE_PINFINDER
PinFinder_setup();
#endif
#ifdef ENABLE_CONTROLS
Controls_setup();
Controls_handler(controlsCallback);
#endif
#ifdef INCLUDE_LED
Led_setup();
FastLED.setBrightness(128);
hanglamp.status(CRGB(0xFF00FF));
#endif
hanglamp.setup();
#ifdef ENABLE_WIFI
Wifi_setup();
#endif
#ifdef INCLUDE_LED
hanglamp.status(CRGB(0x00FFFF));
hanglamp.status(CRGB(0x000000));
#endif
#ifdef ENABLE_MQTT
MQTT_setup();
#endif
#ifdef ENABLE_OTA
OTA_setup();
#endif
#ifdef INCLUDE_LED
hanglamp.status(CRGB(0x00FFFF));
#endif
delay(1000);
hanglamp.status(CRGB::Black);
}
void loop() {
#ifdef ENABLE_OTA
OTA_loop();
#endif
#ifdef ENABLE_PINFINDER
PinFinder_loop();
#endif
delay(1000);
String command;
while(Serial.available()) {
command = Serial.readString();// read the incoming data as string
Serial.print("Have command: ");
Serial.println(command);
int index = command.indexOf(":");
if(index >= 0){
String name = command.substring(0, index);
Serial.print("Have command name: ");
Serial.println(name);
#ifdef INCLUDE_LED
if(name.equals("c")){
//c:0xff4000
//c:0xff0000
//c:0x00ff00
//c:0x0000ff
String color = command.substring(index+1);
if(color.startsWith("0x")){
color = color.substring(2);
}
int value = strtol(color.c_str(), NULL, 16);
CRGB target;
target.r = (value >> 16) & 0xFF;
target.g = (value >> 8) & 0xFF;
target.b = (value >> 0) & 0xFF;
hanglamp.setColor(target);
}
#endif
}
}
}