Compare commits

...

6 Commits

16 changed files with 222 additions and 93 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@
src/config.h
src/tools/*.gif
include/config.h
.piolibdeps
.pioenvs

57
README.md Normal file
View File

@ -0,0 +1,57 @@
# pitrix
## What is pitrix?
pitrix is a software to run on an ESP8266 microncontroller connected
to a LED matrix. It will display the time and a few other nice effects
and stuff.
pitrix fetches the current time via NTP, is controllable via MQTT and
can be flashed over-the-air, so you don't need to disassemble your
nice-looking LED matrix everytime you want to update the software.
## How to use
Checkout the code, rename `include/config.sample.h` to `include/config.h`
and edit it to match your preferences / environment.
Then compile and flash it, preferably using PlatformIO.
## Control it
Currently, control is possible via MQTT and / or HTTP REST API.
To use MQTT, you have to define `MQTT_ENABLE` and configure your MQTT sever's credentials. MQTT_TOPIC` is set in `include/config.h` and defaults to `pitrix`.
To use the HTTP REST API, you have to define HTTP_SERVER_ENABLE and set a port number
to listen on (80 is set by default).
Possible commands / topics are:
* `MQTT_TOPIC/mode` / `POST /mode` lets you select an effect to show. See `src/effects.cpp`
for a list. Default effect is `cycle`, which will cycle through some of
the available effects. Another effect is `off`, which will just display
black, effectively turning the display off. (pitrix stays running, so you
can turn it on again by simply selecting another mode.)
* `MQTT_TOPIC/brightness` / `POST /brightness` sets the brightness of the display. Valid values
are between 1 (darkest possible setting) and 255 (maximum brightness).
* `MQTT_TOPIC/reboot` / `POST /reboot` reboots pitrix. Send any value.
You can set retained values to have pitrix read them at startup, effectively
setting a default effect or brightness. (Do NOT set a retained value for
`MQTT_TOPIC/reboot` unless you want pitrix to reboot all the time.)
## Monitor it
The current status ("ONLINE" or "OFFLINE") of pitrix will be set at
`MQTT_TOPIC/status`.
If you enabled `MQTT_REPORT_METRICS`, metrics are sent via MQTT every 15
seconds:
* `MQTT_TOPIC/free_heap` contains the free heap memory in Bytes.
* `MQTT_TOPIC/uptime` contains the uptime of pitrix in seconds.
* `MQTT_TOPIC/fps` contains the currently reached frames per second.
If you enabled HTTP server, you can always make GET requests to `/free_heap`, `/uptime` or `/fps` to get those values.
If you enabled `DEBUG`, log messages will be sent to `MQTT_TOPIC/log`.

View File

@ -1,39 +0,0 @@
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

View File

@ -4,36 +4,40 @@
#define FASTLED_INTERNAL
#include <FastLED.h>
//#define DEBUG
//#define DEBUG // Uncomment this to enable Debug messages via Serial and, if enabled, MQTT.
//#define CONFIG_USABLE // Uncomment this by removing the // at the beginning!
#define WIFI_SSID "..."
#define WIFI_PASS "..."
#define WIFI_SSID "..." // SSID of the wifi to connect to
#define WIFI_PASS "..." // Password of the wifi
#define LED_WIDTH 16
#define LED_HEIGHT 16
#define LED_COUNT 256
#define LED_TYPE WS2812B
#define DATA_PIN 14
#define COLOR_ORDER GRB
#define BRIGHTNESS 20 // Can be overwritten via MQTT_TOPIC_BRIGHTNESS
#define TEMPORAL_DITHERING 0
#define LED_WIDTH 16 // Number of LEDs in horizontal direction
#define LED_HEIGHT 16 // Number of LEDs in vertical direction
#define LED_COUNT 256 // Total number of LEDs. WIDTH*HEIGHT.
#define LED_TYPE WS2812B // Type of LEDs
#define DATA_PIN 14 // PIN the LEDs are connected to on the microcontroller
#define COLOR_ORDER GRB // Order of the colors of the LEDs. If you get unexpected colors, you should change this.
#define BRIGHTNESS 20 // Default brightness of the LEDs. 1 (lowest)-255 (brightest)
#define TEMPORAL_DITHERING 0 // Use temporal dithering. Can lead to flickering.
#define LED_MAX_MILLIAMPS 0 // If your power supply is too small, you can set this to a maximum mA value. FastLED should then honor this. Setting it to 0 disables this limit.
#define NTP_SERVER "pool.ntp.org"
#define NTP_INTERVAL 300000
#define NTP_OFFSET 7200
#define NTP_SERVER "pool.ntp.org" // NTP server to use to fetch the current time
#define NTP_INTERVAL 300000 // Interval in ms to update the time from the NTP server. 300000 ms = 5 minutes
#define NTP_OFFSET 7200 // Offset of your local time from UTC in seconds. Germany, daylight savings time = 2 hours = 7200 seconds
#define MQTT_ENABLE
#define MQTT_SERVER "..."
#define HTTP_SERVER_ENABLE
#define HTTP_SERVER_PORT 80
#define MQTT_ENABLE // Use MQTT. Add slashes to the start of the line to disable MQTT completely.
#define MQTT_SERVER "..." // Data for connecting to the MQTT server
#define MQTT_PORT 1883
#define MQTT_USER "..."
#define MQTT_PASS "..."
#define MQTT_TOPIC "pitrix/" // MQTT-Topic to listen to. Must not start with a slash, but must end with one."
#define MQTT_REPORT_METRICS
#define MQTT_TOPIC "pitrix/" // MQTT topic to listen to. Must not start with a slash, but must end with one.
#define MQTT_REPORT_METRICS // Whether to report metrics via MQTT. Disable if unwanted.
#define MQTT_TOPIC_WEATHER "accuweather/pitrix/" // MQTT topic to listen for weather data. Must not start with a slash, but must end with one.
#define HOSTNAME "pitrix-%08X"
#define OTA_STARTUP_DELAY 10 // How many seconds to wait at startup. Set to 0 to disable.
#define HOSTNAME "pitrix-%08X" // Hostname of the ESP to use for OTA and MQTT client id. %08X will be replaced by the chip id.
#define OTA_STARTUP_DELAY 10 // How many seconds to wait at startup. This is useful to prevent being unable to flash OTA by a bug in the code. Set to 0 to disable.
#define FPS 50
#define SHOW_TEXT_DELAY 100

16
include/http_server.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "config.h"
#ifdef HTTP_SERVER_ENABLE
#include "my_wifi.h"
#if defined ( ESP8266 )
extern ESP8266WebServer http_server;
#elif defined ( ESP32 )
extern ESP32WebServer http_server;
#endif
void http_server_setup();
void http_server_loop();
#endif

19
include/my_wifi.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "config.h"
#if defined( ESP8266 )
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#elif defined( ESP32 )
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <ESP32WebServer.h>
#endif
#include <WiFiUdp.h>
void wifi_setup();

View File

@ -1,7 +1,7 @@
#pragma once
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "my_wifi.h"
#include "config.h"
extern NTPClient ntpClient;

View File

@ -1,9 +1,6 @@
#ifndef ota_H
#define ota_H
#pragma once
#include <ArduinoOTA.h>
void ota_setup();
void ota_loop();
#endif

View File

@ -1,6 +0,0 @@
#ifndef wifi_H
#define wifi_H
void wifi_setup();
#endif

View File

@ -19,6 +19,7 @@ lib_deps =
https://github.com/fabianonline/FastLED.git
https://github.com/fabianonline/simplelist.git
https://github.com/fabianonline/NTPClient.git
ESP8266WebServer
[env:ota]
upload_port = 10.10.2.78
@ -39,4 +40,7 @@ lib_deps = ${extra.lib_deps}
platform = espressif32
board = esp32dev
framework = arduino
lib_deps = ${extra.lib_deps}
lib_deps =
${extra.lib_deps}
ESP32WebServer
WiFiClient

View File

@ -6,4 +6,7 @@ void fastled_setup() {
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, LED_COUNT).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
FastLED.setDither(TEMPORAL_DITHERING);
if (LED_MAX_MILLIAMPS > 0) {
FastLED.setMaxPowerInVoltsAndMilliamps(5, LED_MAX_MILLIAMPS);
}
};

80
src/http_server.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "config.h"
#ifdef HTTP_SERVER_ENABLE
#include "http_server.h"
#include "effects.h"
#if defined( ESP8266 )
ESP8266WebServer http_server(HTTP_SERVER_PORT);
#elif defined( ESP32 )
ESP32WebServer http_server(HTTP_SERVER_PORT);
#endif
void http_server_400() {
http_server.send(400);
}
void http_server_setup() {
PGM_P text_plain = PSTR("text/plain");
http_server.on("/", HTTP_GET, [&](){
LOGln("HTTP * GET /");
http_server.send_P(200, text_plain, PSTR("Welcome to pitrix."));
});
http_server.on("/free_heap", HTTP_GET, [&](){
LOGln("HTTP * GET /free_heap");
http_server.send(200, "text/plain", String(ESP.getFreeHeap()));
});
http_server.on("/uptime", HTTP_GET, [&](){
LOGln("HTTP * GET /uptime");
http_server.send(200, "text/plain", String(millis()/1000));
});
http_server.on("/fps", HTTP_GET, [](){
LOGln("HTTP * GET /fps");
http_server.send(200, "text/plain", String(FastLED.getFPS()));
});
http_server.on("/reboot", HTTP_POST, [](){
LOGln("HTTP * POST /reboot");
ESP.restart();
});
http_server.on("/brightness", HTTP_POST, [&](){
LOG("HTTP * POST /brightness with value "); LOGln(http_server.arg("plain"));
if (!http_server.hasArg("plain")) {
http_server.send_P(400, text_plain, PSTR("No brightness given"));
return;
}
long val = http_server.arg("plain").toInt();
if (val==0 || val>255) {
http_server.send_P(400, text_plain, PSTR("New value out of bounds. (1-255)"));
return;
}
FastLED.setBrightness(val);
http_server.send(200, "text/plain", "OK");
});
http_server.on("/mode", HTTP_POST, [&](){
LOGln("HTTP * POST /mode with value "); LOGln(http_server.arg("plain"));
if (!http_server.hasArg("plain")) {
http_server.send_P(400, text_plain, PSTR("No effect given."));
return;
}
String val = http_server.arg("plain");
for (int i=0; i<effects->size(); i++) {
EffectEntry e = effects->get(i);
if (val.compareTo(e.name)==0) {
current_effect->stop();
current_effect = e.effect;
current_effect->start();
http_server.send(200, "text/plain", "OK");
return;
}
}
http_server.send_P(400, text_plain, PSTR("Unknown effect."));
});
http_server.begin();
}
void http_server_loop() {
http_server.handleClient();
}
#endif

View File

@ -5,13 +5,7 @@
#pragma message "MQTT_ENABLE is false. Skipping MQTT."
#else
#if defined( ESP8266 )
#include <ESP8266WiFi.h>
#elif defined( ESP32 )
#include <WiFi.h>
#else
#error "Neither ESP32 nor ESP8266 set..."
#endif
#include "my_wifi.h"
#include <PubSubClient.h>
#include "EffectEntry.h"
#include "Effect.h"
@ -58,7 +52,7 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
topic.remove(0, strlen(MQTT_TOPIC)); // Strip MQTT_TOPIC from the beginning
LOG("MQTT * Remaining topic is: "); LOGln(topic.c_str());
if (topic.compareTo("free_heap")==0 || topic.compareTo("uptime")==0 || topic.compareTo("status")==0) {
if (topic.compareTo("free_heap")==0 || topic.compareTo("uptime")==0 || topic.compareTo("status")==0 || topic.compareTo("fps")==0) {
// Ignore our own messages.
return;
}

View File

@ -1,12 +1,6 @@
#include <ArduinoOTA.h>
#if defined( ESP8266 )
#include <ESP8266mDNS.h>
#elif defined( ESP32 )
#include <ESPmDNS.h>
#else
#error Neither ESP32 nor ESP8266 set!
#endif
#include "my_wifi.h"
#include <ArduinoOTA.h>
#include "config.h"

View File

@ -4,13 +4,14 @@
#include "ntp.h"
#include "config.h"
#include "animations.h"
#include "wifi.h"
#include "my_wifi.h"
#include "ota.h"
#include "my_fastled.h"
#include "EffectEntry.h"
#include "my_mqtt.h"
#include "functions.h"
#include "effects.h"
#include "http_server.h"
uint8_t starting_up = OTA_STARTUP_DELAY;
int loop_timeouts = 0;
@ -26,6 +27,9 @@ void setup() {
ota_setup();
fastled_setup();
ntpClient.begin();
#ifdef HTTP_SERVER_ENABLE
http_server_setup();
#endif
#ifdef MQTT_ENABLE
mqtt_setup();
#endif
@ -57,6 +61,9 @@ void loop() {
#ifdef MQTT_ENABLE
mqtt_loop();
#endif
#ifdef HTTP_SERVER_ENABLE
http_server_loop();
#endif
EVERY_N_MILLISECONDS(100) {
baseHue++;
@ -77,6 +84,7 @@ void loop() {
EVERY_N_SECONDS(15) {
mqtt_publish("free_heap", ESP.getFreeHeap());
mqtt_publish("uptime", millis()/1000);
mqtt_publish("fps", FastLED.getFPS());
}
#endif // MQTT_REPORT_METRICS

View File

@ -1,12 +1,8 @@
#include <Arduino.h>
#if defined( ESP8266 )
#include <ESP8266WiFi.h>
#elif defined( ESP32 )
#include <WiFi.h>
#endif
#include "wifi.h"
#include "my_wifi.h"
#include "config.h"
void wifi_setup() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);