work in progress

This commit is contained in:
Daan Meijer 2024-06-05 22:45:06 +02:00
commit b913fca342
21 changed files with 734 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
src/WifiSettings.h
vue/node_modules
vue/.vite
data/public

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

30
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"files.associations": {
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"deque": "cpp",
"list": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"iterator": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"string_view": "cpp",
"functional": "cpp",
"istream": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"regex": "cpp",
"tuple": "cpp",
"variant": "cpp",
"random": "cpp"
}
}

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Daan Meijer
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.

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Hanglamp
## Intro
Led strip driver for dual WS2812B strip of 46 leds

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

34
platformio.ini Normal file
View File

@ -0,0 +1,34 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp12e]
platform = espressif8266
board = esp12e
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
khoih-prog/ESPAsync_WiFiManager
bblanchon/ArduinoJson@^6.19.4
vshymanskyy/Preferences@^2.0.0
mbed-multitech/flash-fs
fastled/FastLED@^3.6.0
arkhipenko/TaskScheduler@^3.7.0
drk/PubSubClient@^2.8
khoih-prog/ESPAsync_WiFiManager@^1.15.1
devyte/ESPAsyncDNSServer@^1.0.0
me-no-dev/ESPAsyncUDP
makuna/NeoPixelBus @ ^2.8.0
lib_ldf_mode = chain+
monitor_filters = default, esp8266_exception_decoder
board_build.filesystem = littlefs
board_build.f_cpu = 80000000L

152
src/Hanglamp.cpp Normal file
View File

@ -0,0 +1,152 @@
#include "Led.h"
#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
#include <TaskScheduler.h>
#include "MQTT.h"
#include "Wifi.h"
#include "FS.h"
#include <LittleFS.h>
#include "PinFinder.h"
void feedWatchdog(){
ESP.wdtFeed();
}
bool blinkStatus = false;
void blink(){
blinkStatus = !blinkStatus;
digitalWrite(LED_BUILTIN, blinkStatus);
}
CRGB colorTable[] = {
CRGB::Red,
CRGB::Blue,
CRGB::Green,
CRGB::Purple,
CRGB::Turquoise,
CRGB::Yellow
};
uint8_t colorIndex = 0;
void colors(){
colorIndex++;
if(colorIndex >= (sizeof(colorTable) / sizeof(CRGB))){
colorIndex = 0;
}
Serial.printf("colorIndex: %d\n", colorIndex);
jumpTo(colorTable[colorIndex]);
}
Scheduler runner;
Task taskBlink(1000, TASK_FOREVER, &blink);
Task taskColors(1000, TASK_FOREVER, &colors);
// Task taskFade(1, TASK_FOREVER, &fadeTask);
// Task taskFeedWatchdog(1000, TASK_FOREVER, &feedWatchdog);
void setup() {
Serial.begin(115200);
delay(500);
if(!LittleFS.begin()){
Serial.println("LittleFS Mount Failed");
return;
}
// runner.init();
Serial.println("Initialized scheduler");
runner.addTask(taskBlink);
runner.addTask(taskColors);
// runner.addTask(taskFade);
// runner.addTask(taskFeedWatchdog);
// taskBlink.enable();
taskColors.enable();
// taskFade.enable();
// taskFeedWatchdog.enable();
Serial.println("Scheduled tasks");
// PinFinder_setup();
Led_setup();
jumpTo(CRGB(0xFF00FF));
Wifi_setup();
jumpTo(CRGB(0x00FFFF));
jumpTo(CRGB(0x000000));
MQTT_setup();
// OTA_setup();
jumpTo(CRGB(0x00FFFF));
ESP.wdtEnable(10000);
}
void loop() {
MQTT_loop();
// OTA_loop();
// PinFinder_loop();
// runner.execute();
colors();
delay(100);
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);
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);
}
}
}
}

117
src/Led.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "Led.h"
CRGB led;
CRGB source;
CRGB target;
CRGB strip1[STRIP_LENGTH];
CRGB strip2[STRIP_LENGTH];
int fadeStart = 0;
void fadeTo(const CRGB & dest){
Serial.println("fadeTask is not implemented");
return;
char buffer[80];
if(led.r == dest.r && led.g == dest.g && led.b == dest.b){
return;
}
snprintf(buffer, sizeof(buffer), "Have a new target: 0x%02X%02X%02X (old color 0x%02X%02X%02X)\n", dest.r, dest.g, dest.b, led.r, led.g, led.b);
Serial.println(buffer);
source = led;
target = dest;
fadeStart = millis();
}
void displayLed(){
for(uint8_t index = 0; index < STRIP_LENGTH; 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++){
// Serial.printf("Led 2:%02d 0x%02x%02x%02x\n", index, strip2[index].r, strip2[index].g, strip2[index].b);
}
FastLED.show();
}
void jumpTo(const CRGB & dest){
for(uint8_t index = 0; index < STRIP_LENGTH; index++){
strip1[index] = dest;
strip2[index] = dest;
}
Serial.printf("Set color to 0x%02x%02x%02x\n", dest.r, dest.g, dest.b);
displayLed();
}
void fadeTask(){
Serial.println("fadeTask is not implemented");
return;
if(fadeStart == 0){
return;
}
float fadeInMillis = millis() - fadeStart;
float progress = (fadeInMillis / 1000) / FADE_PERIOD;
fract8 fract = progress * 256;
if(progress >= 1.0f){
led = target;
source = target;
fadeStart = 0;
}else{
led = source.lerp8(target, fract);
displayLed();
}
}
void Led_setup(){
// pinMode(PIN_STRIP1, OUTPUT);
// pinMode(PIN_STRIP2, OUTPUT);
// analogWriteRange(255);
// pinMode(PIN_BUILTIN_LED, OUTPUT);
// digitalWrite(PIN_BUILTIN_LED, HIGH);
FastLED.addLeds<WS2812B, PIN_STRIP1>(strip1, STRIP_LENGTH);
FastLED.addLeds<WS2812B, PIN_STRIP2>(strip2, STRIP_LENGTH);
}
void Led_loop(){
strip2[0] = CRGB(255, 0, 0);
FastLED.show();
delay(500);
strip2[1] = CRGB(0, 255, 0);
FastLED.show();
delay(500);
strip2[2] = CRGB(0, 0, 255);
FastLED.show();
delay(500);
strip2[5] = CRGB(150, 0, 255);
FastLED.show();
delay(500);
strip2[9] = CRGB(255, 200, 20);
FastLED.show();
delay(500);
strip2[14] = CRGB(85, 60, 180);
FastLED.show();
delay(500);
strip2[19] = CRGB(50, 255, 20);
FastLED.show();
delay(500);
}

26
src/Led.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "stdint.h"
#include <cstdio>
#include <Arduino.h>
#include <FastLED.h>
#define PIN_BUILTIN_LED 2
#define PIN_STRIP1 0
#define PIN_STRIP2 2
#define STRIP_LENGTH 46
#define FADE_PERIOD 3.0f
void Led_setup();
void Led_loop();
void jumpTo(const CRGB & dest);
void fadeTo(const CRGB & dest);
void fadeTask();

117
src/MQTT.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "MQTT.h"
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
WiFiClient espClient;
PubSubClient client(espClient);
std::vector<SubscribedChannel> * channels = new std::vector<SubscribedChannel>();
char mqtt_server[40] = "manus";
char mqtt_port[6] = "1883";
void connect() {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "Konijntje-";
clientId += String(ESP.getChipId());
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// ... and resubscribe
// if(topic != NULL){
// client.subscribe(topic);
// }
} else {
Serial.print("failed, rc=");
Serial.println(client.state());
}
}
void MQTT_publish(const char * topic, String str){
char * buff = new char[str.length() + 1];
str.toCharArray(buff, str.length() + 1);
MQTT_publish(topic, buff);
delete buff;
}
void MQTT_publish(const char * topic, const char * msg){
client.publish(topic, msg);
}
void (*pCallback)(uint8_t *, unsigned int) = NULL;
void MQTT_subscribe(char * topic, void (*callback)(uint8_t *, unsigned int)){
Serial.println("MQTT_subscribe");
Serial.printf("Topic: [%s]\n", topic);
SubscribedChannel * channel = new SubscribedChannel();
channel->topic = new String(topic);
channel->callback = callback;
client.subscribe(topic);
channels->push_back(*channel);
}
void MQTT_callback(char* topic, uint8_t * payload, unsigned int length){
Serial.println("MQTT_callback");
for (auto channel = channels->begin(); channel != channels->end(); ++channel){
if(channel->topic->equals(topic)){
channel->callback(payload, length);
}
}
}
void MQTT_setup(){
Serial.println("MQTT_init");
client.setServer(mqtt_server, String(mqtt_port).toInt());
client.setCallback(MQTT_callback);
// Serial.println("MQTT_init after callback");
// char buff[256];
// sprintf(buff, "%08x", _pCallback);
// Serial.println(buff);
connect();
}
void MQTT_loop(){
#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);
}
}
client.loop();
}

21
src/MQTT.h Normal file
View File

@ -0,0 +1,21 @@
#include "settings.h"
#include "Arduino.h"
using namespace std;
struct SubscribedChannel {
String * topic;
void (*callback)(uint8_t *, unsigned int);
};
void MQTT_publish(const char * topic, String str);
void MQTT_publish(const char * topic, const char * msg);
void MQTT_loop();
void MQTT_setup();

33
src/PinFinder.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "PinFinder.h"
#include "Arduino.h"
char pins[] = {
0,
2,
4,
5,
12,
13,
14,
15,
16,
};
void PinFinder_setup(){
for(int index=0; index < sizeof(pins); index++){
auto pin = pins[index];
Serial.printf("Setting pin %d to OUTPUT\n", pin);
pinMode(pin, OUTPUT);
}
}
void PinFinder_loop(){
for(int index=0; index < sizeof(pins); index++){
auto pin = pins[index];
Serial.printf("Setting pin %d high\n", pin);
digitalWrite(pin, HIGH);
delay(1000);
Serial.printf("Setting pin %d low\n", pin);
digitalWrite(pin, LOW);
}
}

2
src/PinFinder.h Normal file
View File

@ -0,0 +1,2 @@
void PinFinder_setup();
void PinFinder_loop();

0
src/Strip.h Normal file
View File

42
src/Wifi.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <ESP8266WiFi.h>
#include <ESPAsync_WiFiManager.h>
#include <Arduino.h>
#include "WifiSettings.h"
void Wifi_setup_softap(){
Serial.print("Setting soft-AP ... ");
boolean result = WiFi.softAP("ESPsoftAP_01", "pass-to-soft-AP");
if(result == true)
{
Serial.println("Ready");
}
else
{
Serial.println("Failed!");
}
}
void Wifi_setup(){
WiFi.mode(WIFI_STA);
//TODO:
WiFi.begin(WIFI_ESSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

3
src/Wifi.h Normal file
View File

@ -0,0 +1,3 @@
void Wifi_setup();

View File

@ -0,0 +1,2 @@
#define WIFI_ESSID "YOUR ESSID HERE"
#define WIFI_PASSWORD "YOUR PASSWORD HERE"

7
src/settings.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef SETTINGS_H
#define SETTINGS_H
extern char mqtt_server[40];
extern char mqtt_port[6];
#endif

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html