Skip to content

Commit

Permalink
Docs and bugfixes for V1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
DerEffi committed Jun 30, 2023
1 parent d113d32 commit 4354e11
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 126 deletions.
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
# Pixelart
# <p align="center">DerEffi's Pixelart Display</p>

## Usage
Nobody reads the instructions...
Just plug it in :P
<img src="./images/overview.jpg" width="400" height="400" style="display: block;margin: auto;" />

## Installation
TBD
## About

## Notes
- image upload in 64x64 (browser downscaling not that great)
- image upload in rgb colorspace (browser color conversion not that great)
- no alpha channel (cant be displayed by led panel and is ignored)
This project is an ESP32 Display Matrix for displaying images, time and social stats on a 64x64 LED Matrix Panel (HUB75E). An overview about the functionalities can be found at the Project Site [pixelart.dereffi.de](http://pixelart.dereffi.de).

## Disclaimer

This project is not a product, but rather a diy project. I won't sell it. I probably won't do another one at all. There are some minor issues/inconviniences that I plan to address in the future, but I can not make any promises on if or when that could happen.

That being said, in general I'm happy with the current state (althought it's not perfect) and the core functionality works as expected. You can use my code to rebuild it yourself or use parts of the code for your own project. If there are any issues, I'm pleased to help. If you have any solutions I'm even more pleased if you contribute.

## Usage/Deployment

The project consist of three parts:
- the controller for the display: [/pixelart-controller](./pixelart-controller/)
- the webinterface for remote control of the display: [/pixelart-interface](./pixelart-interface/)
- the socials api for retrieving social data from different platforms: [/pixelart-api](./pixelart-api/)

The documentations for these projects can be found in the different subdirectories as well as additional files for api, schematics and my dev board pinout under `/docs`.
An already compiled version of the firmware and the webinterface for the device can be found on the project site for download if you plan to use it as is.
Please be aware, that I won't be giving out any api-keys for my hosted social-api service (more on that under [/pixelart-api](./pixelart-api/README.md)), so you will have to host this on your own.

## Credits

Among a few other libraries I use in this project, thanks especially to:
- [mrfaptastic's ESP32/HUB75 Library](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA) used to output on the LED matrix at all
- [me-no-dev's Async Webserver library](https://github.com/me-no-dev/ESPAsyncWebServer) for making the webinterface possible
- [khoih-prog's Async HTTP Request Library](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic) for retrieving social data on the controller
- [pgrimaud's instagram fetcher](https://github.com/pgrimaud/instagram-user-feed) for the retrieval of instagram data. Even if I don't use this library directly, I used it as a template for the authentication agains instagram apis

## Project Site
[pixelart.dereffi.de](pixelart.dereffi.de)

[pixelart.dereffi.de](http://pixelart.dereffi.de)

## Author

[DerEffi](https://dereffi.de)
[info@dereffi.de](mailto:info@dereffi.de)
Binary file added images/overview.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions pixelart-api/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
APP_NAME="DerEffi's Pixelart - API"
APP_ENV=local
APP_KEY=base64:aFlsyu39KAHIbRTlB2COTAEL+/VqK/pcVmEEqECJEgI=
APP_DEBUG=true
APP_URL=https://api.pixelart.dereffi.de
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=localhost

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
Expand Down
81 changes: 23 additions & 58 deletions pixelart-api/README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,31 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
# <p align="center">Pixelart - Socials API</p>

<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## About

## About Laravel
This Laravel App acts as service for the ESP32 to receive data from youtube, twitch and instagram. The authentication against this platforms is completely handled by this App, because of the limitations of the microcontroller.

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
## Installation

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
1. Install php on your system. Easiest with a server package like XAMPP or WAMPP also including a database server for later usage/debugging
1. Install php [composer](https://getcomposer.org/) on your system
1. Install package dependencies by executing `composer install` in the app directory
1. Copy the `.env.example` to `.env` and customize the environment settings
- Add a database connection
- Add credentials for a [Twitch App](https://dev.twitch.tv/console/extensions/create)
- Add credentials for a Youtube/GoogleAPIs App. You need to add the capabilities of [YouTube Data API v3](https://developers.google.com/youtube/v3/getting-started) to your project in the google cloud console.
- Add credentials for an instagram user. (No app, can be any user with permissions to view the account you want to display)
1. Generate a new encryption key with `php artisan key:generate`
1. Add an API key for authentication in the database by either manually adding it in the table or using the DatabaaseSeeder: `php artisan db:seed`

Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Deployment

## Learning Laravel
You can host the app like any other [Laravel App](https://laravel.com/docs/9.x/deployment) by simply copying the files in the hosting directory of your webserver by i.e.
- Using a webserver like Apache or Nginx directly
- Using a webserver package like XAMPP or WAMPP
- Deploying on a homeserver like a Raspberry Pi
- Deploying on a webserver/shared webhosting

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
# Usage

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
You can find a [openapi documentation](../docs/API/openapi.yml) and a [Postman Collection](../docs/API/Pixelart.postman_collection.json) about the available endpoints under [/docs/API](../docs/API/openapi.yml).
Make sure to add the `Authorization` Header with the API key from the Installation before makin any calls.
48 changes: 48 additions & 0 deletions pixelart-controller/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# <p align="center">Pixelart - Controller</p>

## About

This is the firmware for the controller of the led matrix.

## Hardware compatibility

For the firmware you need an ESP32-S3 specifically. For other versions either RAM or GPIO Pins are missing. I used a DevKit with the Onboard LED on Pin 48 for this project (DevkitC V1), by swapping RGB-LED Pin on your devboard with pin 48 in [main.h](./src/main.h) and your hardware you should be able to use different devkits as well.

The project should work with any SPI SD-Card reader connected to the according pins and any I2C RTC Module. The device should work without both of these, but can't use the webinterface and displaying images if you are missing an sd card and you would need to set the clock manually every time you start the device or have it connected to wifi to update itself on start if you don't use any RTC module.

For the display, I used a 64x64 LED Matrix connected via HUB75E interface. Although you should be able to use any HUB75 display, you will have to customize a big part of the code when using other dimensions, since I hardcoded most of the bitmaps and positions to that resolution.

## Wiring

If you have the components described above, you can wire them according to the main.h file. See [Customization](#customization) for more information on that below.

## Installation

Development is done using [Visual Studio Code](https://code.visualstudio.com/) with the [PlatformIO extension](https://platformio.org/install/ide?install=vscode). The dependencies should be installed on your first build.

Under `src/` copy the `main.h.example` and rename it to `main.h`.

## Customization

Be aware that any changes you make might prevent you from using [Updates](#updates). For more information see below.

In the `src/main.h` file you can set the Pins used by the controller for the attached devices (SPI / I2C / HUB75E and Interrupts) as well as the factory settings for wifi, time and the socials API. If you plan to use the socials functions, make sure to deploy the socials-api app and setting the server and api key. The social channels can be configured by the webinterface later.

In the `platform.ini` file you can change the build option `DPIXEL_COLOUR_DEPTH_BITS` for the devkit-c profile. Even though the colors might not be optimal, the sweetspot for me was to set it to `5`. 6 or more requires the panel to run at a lower refresh rate, with induces the typical LED flickering on cameras and I think you can even see it by eye.

You can override the socials API Key and hosted Wifi password on your device by copying the two files in the `data` folder and removing `.example` from the filename. The configuration from these files are prioritised over everything else and therefore the only ones not changing with any updates you perform. If you want to update these values, edit the files and repeat the first step under [Deployment](#deployment).

## Deployment

1. Deploy the configuration files to your ESP32-S3 by selecting the build profile (`devkit-c` if you are using my provided configuration) in the PlatformIO menu. Under `Platform` first Build the Filesystem Image and then Upload it to your device connected via Serial/USB. This uploads the data folder to the devices filesystem.
1. Deploy the firmware under `General > Upload` the same way.

## Updates

! Updates will override any customization except from files of the `data` folder. User settings made via webinterface will be kept until factory reset !

Although I plan to revisit this project, since there are some issues I still want to resolve. I can't make any promises on when or if updates will be made or if the hardware configuration will stay the same, since there are some "janky" solutions in place right now, but if you plan to deploy this project yourself, you might be able to use the update functionalities either via OTA or SD-Card on your own by changing the update server.

When using your own update server, make sure to place the `version.json` file for the version metadata alongside your `firmware.bin` inside `www.your-update.server/firmware/`.

On more information on how to perform updates visit the webinterface startpage or [http://pixelart.dereffi.de/](http://pixelart.dereffi.de/#/#updates)
1 change: 1 addition & 0 deletions pixelart-controller/data/socials.conf.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f8f1302b-3e0d-48cd-a6c4-5ffe18bbb6d6
2 changes: 1 addition & 1 deletion pixelart-controller/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ lib_ignore =
WebServer_ESP32_W5500
ESPAsyncUDP
build_flags =
-DPIXEL_COLOUR_DEPTH_BITS=6
-DPIXEL_COLOUR_DEPTH_BITS=5
-DARDUINO_ESP32S3_DEV
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
Expand Down
74 changes: 48 additions & 26 deletions pixelart-controller/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ bool clock_year = true;
bool wifi_connect = WIFI_CONNECT_DEFAULT;
bool wifi_host = WIFI_HOST_DEFAULT;
bool wifi_setup_complete = true;
bool ms_wifi_scan_requested = 0;
unsigned long ms_wifi_scan_requested = 0;
unsigned long ms_wifi_scan_last = 0;
bool wifi_scan_pending = false;
std::vector<available_network> available_networks;
char* wifi_ssid = strdup(WIFI_SSID_DEFAULT);
Expand Down Expand Up @@ -314,14 +315,16 @@ void on_socials_response(){
const char* c = socials_response_array[i]["c"].as<const char*>();
const char* f = socials_response_array[i]["f"].as<const char*>();
const char* v = socials_response_array[i]["v"].as<const char*>();

socials_channel channel = {
t ? strdup(t) : strdup(""),
d ? strdup(d) : c ? strdup(c) : strdup(""),
f ? strdup(f) : strdup("0"),
v ? strdup(v) : strdup("0")
};
socials_channels.emplace_back(channel);

if(d || c) {
socials_channel channel = {
t ? strdup(t) : strdup(""),
d ? strdup(d) : c ? strdup(c) : strdup(""),
f ? strdup(f) : strdup("0"),
v ? strdup(v) : strdup("0")
};
socials_channels.emplace_back(channel);
}
}
}

Expand Down Expand Up @@ -1161,9 +1164,11 @@ void display_social_channel(char* type, char* channel, char* subs, char* views)
panel->setTextColor(0xFFFF);
panel->setTextSize(1);

panel->getTextBounds(channel, 0, 0, &x1, &y1, &width, &height);
panel->setCursor(64 > width ? .5 * (64 - width) : 0, 42);
panel->write(channel);
if(channel && strlen(channel) > 0) {
panel->getTextBounds(channel, 0, 0, &x1, &y1, &width, &height);
panel->setCursor(64 > width ? .5 * (64 - width) : 0, 42);
panel->write(channel);
}

int textbox_start_position = 0;
int textbox_offset = 0;
Expand Down Expand Up @@ -1515,15 +1520,28 @@ void IRAM_ATTR trigger_rot3_btn() {

//Load config data from internal filesystem
void spiffs_setup() {
if(SPIFFS.begin() && SPIFFS.exists("/wifi.conf")) {
File file = SPIFFS.open("/wifi.conf");
if(!file.isDirectory()) {
size_t filesize = file.size();
char buffer[filesize];
file.readBytes(buffer, filesize);
buffer[filesize] = '\0';
free(wifi_ap_password);
wifi_ap_password = strdup(buffer);
if(SPIFFS.begin()) {
if(SPIFFS.exists("/wifi.conf")) {
File file = SPIFFS.open("/wifi.conf");
if(!file.isDirectory()) {
size_t filesize = file.size();
char buffer[filesize];
file.readBytes(buffer, filesize);
buffer[filesize] = '\0';
free(wifi_ap_password);
wifi_ap_password = strdup(buffer);
}
}
if(SPIFFS.exists("/socials.conf")) {
File file = SPIFFS.open("/socials.conf");
if(!file.isDirectory()) {
size_t filesize = file.size();
char buffer[filesize];
file.readBytes(buffer, filesize);
buffer[filesize] = '\0';
free(socials_api_key);
socials_api_key = strdup(buffer);
}
}
}
SPIFFS.end();
Expand Down Expand Up @@ -2875,12 +2893,16 @@ void loop() {
//Wifi scan
if(ms_wifi_scan_requested != 0 && ms_wifi_scan_requested < ms_current && !wifi_scan_pending) {
ms_wifi_scan_requested = 0;
wifi_scan_pending = true;

wifi_setup_complete = true;
WiFi.mode(WIFI_STA);
WiFi.disconnect();
WiFi.scanNetworks(true);
if(ms_wifi_scan_last == 0 || ms_wifi_scan_last + 90000 < ms_current) {
wifi_scan_pending = true;

wifi_setup_complete = true;
WiFi.mode(WIFI_STA);
WiFi.disconnect();
WiFi.scanNetworks(true);
ms_wifi_scan_last = millis();
}
}
if(wifi_scan_pending) {
int networks = WiFi.scanComplete();
Expand Down
Loading

0 comments on commit 4354e11

Please sign in to comment.