Skip to content

Commit

Permalink
Merge pull request #1 from realSixi/main
Browse files Browse the repository at this point in the history
Basic Updates
  • Loading branch information
realSixi authored Apr 23, 2022
2 parents e0d9a8d + 2348e44 commit 7a93238
Show file tree
Hide file tree
Showing 10 changed files with 534 additions and 23 deletions.
65 changes: 65 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
create:
tags:
- v*

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
if: github.repository_owner == 'realSixi' || github.repository_owner == 'ProjektionTV'
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.platformio
key: ${{runner.os}}-${{hashFiles('**/lockfiles')}}
- name: Setup python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Run Platformio
run: pio run
- uses: actions/upload-artifact@v2
if: startsWith(github.ref, 'refs/tags/')
with:
name: firmware-release
path: ./build_output/release/*.bin
upload:
needs: [build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/download-artifact@v2
with:
name: firmware-release
- name: Create draft release
uses: softprops/action-gh-release@v1
with:
draft: True
files: |
*.bin
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@

.pio
.vscode
build_output

src/settings_custom.h
143 changes: 143 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,145 @@
# ProjektionFX

ProjektionFX lässt deine WS2812-LED-Stripes zu Hause im Takt von den DJ Streams von unserem Ilja von [ProjektionTV](https://www.projektion.tv/) aufleuchten!

Besuche uns gerne:
- 📺 Live auf [twitch.tv/projektiontv](https://www.twitch.tv/projektiontv/)
Streams immer *Montag, Mittwoch und Freitag* von 16:00 Uhr bis ca. 20/21 Uhr
- 🤷‍♂️ auf unserem [Discord](https://discord.gg/92JNBJR) - dort tummeln sich viele nette und hilfsbereite ProjektionTV ZuschauerInnen herum. Die beste Anlaufstelle, wenn es Fragen gibt!
- auf der [ProjektionTV Webseite](https://www.projektion.tv/)

# Inhaltsverzeichnis

- 🔌 [Benötigte Hardware](#benötigte-hardware)
- 🛠 [Installation](#installation)
- ⌨️ [mit Entwickeln](#mit-entwickeln)

## Benötigte Hardware
- einen [ESP8266](https://amzn.to/38htUZG)* oder [ESP32](https://amzn.to/38h9P5I)* Mikrocontroller
- einen [WS2812-LED Stripe](https://amzn.to/2LL7WH3)*
- ein paar Kabel, um den ESP und den LED Stripe miteinander zu verbinden
- *Optional:* Wenn dein LED Stripe lang ist, dann solltest du Ihn über ein Netzteil extra mit Strom versorgen!


<sup>*mit Sternchen (\*) gekennzeichnete Links sind Affiliate-/Werbelinks. Wenn du mit diesen einkaufst, dann unterstützt du ProjektionTV! Vielen Dank!*</sup>

## Installation

### Methode 1: Web installer

(tbd)

### Methode 2: Image herunterladen

- Als erstes installiere [esptool.py](https://docs.espressif.com/projects/esptool/en/latest/esp32/) (Benötigt Python und [pip](https://pip.pypa.io/en/stable/installation/))
- Lade die aktuelle Binärdatei von der [Releases](https://github.com/ProjektionTV/ProjektionFX/releases) Seite herunter.
Download-Links für die neusten Versionen:
- [ESP8266 - D1 Mini](https://github.com/realSixi/ProjektionFX/releases/latest/download/ProjektionFX_d1_mini_ESP8266.bin)
- [ESP8266 - NodeMCU](https://github.com/realSixi/ProjektionFX/releases/latest/download/ProjektionFX_nodemcuv2_ESP8266.bin)
- [ESP32 - ESP32Thing](https://github.com/realSixi/ProjektionFX/releases/latest/download/ProjektionFX_esp32thing_ESP32.bin)
- Stelle sicher, dass nur *ein* ESP mit deinem Computer verbunden ist, um nicht aus versehen den falschen ESP zu flashen! Du kannst auch direkt den Port angeben, z.B. `-port COM4` nach dem `write_flash` in den nachfolgenden Befehlen

**ESP8266**
```
esptool.py write_flash 0x0 ./ProjektionFX_XXX.bin
```

**ESP32**

Wenn der ESP32 noch keinen Bootloader hat, muss dieser erst geschrieben werden. Lade einen Bootloader, z.B. von dem [WLED Projekt](https://github.com/Aircoookie/WLED/releases/download/v0.13.1/esp32_bootloader_v4.bin) herunter.

```
esptool.py write_flash 0x0 ./esp32_bootloader_v4.bin
```

Anschließend schreibe das ProjektionFX Image. **Achtung:** Achte darauf, dass hier erst ab dem Offset `0x10000` geschrieben wird!
```
esptool.py write_flash 0x10000 ./ProjektionFX_XXX.bin
```

*Bei manchen ESPs muss der **BOOT** Knopf gedrückt werden, damit ein neues Image geflasht werden kann.*

## Einrichtung

Wenn du ProjektionFX erfolgreich aufgespielt hast, dann öffnet dieser (wenn er an den Strom angeschlossen ist) ein WLAN, über dass du ProjektionFX konfigurieren kannst.

1. Verbinde dich mit dem WLAN **ProjektionFX**, am besten von deinem Handy oder Tablet aus
2. Es öffnet sich eine Seite, um die Konfiguration auszuführen.
Wenn nicht: öffne in deinem Browser die Adresse [http://192.186.4.1](http://192.186.4.1)
3. Klicke auf **Configure WiFi**:
1. Wähle **dein WLAN** aus
2. Trage dein **Passwort** ein
3. Trage die Daten für den ProjektionTV **MQTT Server** ein.
Die *Server-Adresse* sowie Benutzername und Passwort erhälst du entweder im Chat oder du besuchst unseren [Discord-Server](https://discord.gg/92JNBJR)!
4. Tippe auf **Save** um die Einstellungen zu speichern. Der ESP startet nun neu und verbindet sich mit deinem WLAN und empfängt automatisch den Beat von ProjektionTV!


## Mit-Entwickeln

ProjektionFX ist ein Community Projekt - und wir hoffen, dass viele Menschen Lust und Spaß daran haben, uns bei der Entwicklung zu helfen!

Wenn du eine Idee hast und mit-coden möchtest, dann melde dich am besten gerne im [Discord](https://discord.gg/92JNBJR) oder schreibe ein [Ticket](https://github.com/ProjektionTV/ProjektionFX/issues) im GitHub Repository und beschreibe kurz, was du vor hast.

### Effekte Entwickeln

ProjektionFX wird spannend, wenn möglichst viele Effekte - also Abläufe, wie die LEDs abhängig vom Beat der Musik leuchten - entstehen.

Wenn du Lust hast deinen eigenen Effekt zu entwickeln, schau dir mal die bestehenden Effekte, z.B. den `effect_movingdot_simple.h` an.


```cpp
class EffectMovingDotSimple : public Effect
{
public:
static void run(BeatInfo beatInfo, CRGBSet leds, int numLeds)
{
// alle LEDs werden etwas "ausgeschaltet", also dunkler
leds.fadeToBlackBy(100);

// ein rotes Licht, dass auf jeden Beat einmal komplett über alle LEDs läuft
// als erstes wird die Position bestimmt:
// - die Zeit wo wir uns befinden, wird über die Methode beatInfo.animationFrame(1) abgefragt und
// gibt einen Wert von 0 (= bedeutet, wir sind ganz am Anfang, also der Beat kam gerade) bis 1000
// (das heißt wir sind ganz am Ende, der nächste Beat kommt gleich!) zurück
// - die map()-Methode 'mappt' (Dreisatz!) die Werte von animationFrame (0-1000) auf den Bereich von
// 0 bis zu unserer letzten LED (=numLeds)
// - das Ergebnis wird in der Variable redLEDPosition gespeichert
int redLEDPosition = map(beatInfo.animationFrame(1), 0, 1000, 0, numLeds);

// nun schalten wir die LED an der Position redLEDPosition auf rot
leds[redLEDPosition] = CRGB::Red;

// ein grünes Licht, dass in der Zeit von zwei Beat einmal komplett über alle LEDs läuft:
// genauso, wie bei der roten, außer das wir hier beatInfo.animationFrame(2) aufrufen,
// d.h.:
// - bei dem Rückgabewert 0 sind wir auf dem 1. Beat,
// - bei dem Rückgabewert 500 sind wir auf dem 2. Beat
// - bei dem Wert 1000 sind wir wieder ganz kurz vor dem 1. Beat
// Insgesamt braucht die grüne LED immer 2 Beats (bei 120BPM wäre das 1 Sekunde), um über den
// gesamten LED Streifen zu laufen.
int greenLEDPosition = map(beatInfo.animationFrame(2), 0, 1000, 0, numLeds);
leds[greenLEDPosition] = CRGB::Green;


// zum Abschluss noch ein bisschen Weichzeichnen; ist nicht notwendig, aber etwas 'schöner' und weicher,
// wenn der Stripe lang ist. Denn auf jeden Beat über viele LEDs laufen ist schon ganz schön schnell ;)
blur1d(leds, numLeds, 64);
}
};
```
### Bitte beachten:
- ProjektionFX nutzt die großartige Bibliothek [FastLED](https://github.com/FastLED/FastLED); schau dort gerne in die Dokumentation, welche Funktionen / Hilfsfunktionen zur Verfügung stehen!
- ein Effekt darf/sollte **nicht** die Arduino oder FastLED `delay()` Methode nutzen und damit die Ausführung anhalten.
- die "Animation" der Effekte sollte irgendwie von dem Beat abhängig sein. Da die Lieder meist einen 4/4tel Takt haben, ist es meist am wirkungsvollsten, wenn du auf ein 4-faches von dem Beat 'animierst', also indem du der `beatInfo.animationFrame()`-Methode 4, 8, 16, usw. als Parameter übergibst
### ProjektionFX Kern
Momentan ist ProjektionFX ein kleines Grundgerüst, das noch deutlich weiterentwickelt werden muss.
Aktuell werden nur die BPM, also die Beats pro Minute, abgefragt und ausgewertet. Aber das soll nicht so bleiben!
- Synchronisierung mit *deinem* Videobild - so dass deine LEDs nicht nur im richtigen Takt, sondern auch zum richtigen Zeitpunkt auf die Musik reagieren. Dies z.B. über
- eine Photo-Diode und ein optisches Signal im ProjektionTV Videobild
- Synchronisierung, welcher Effekt gerade abgespielt wird
- und vieles mehr :)
71 changes: 71 additions & 0 deletions pio-scripts/rename-releases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
Import('env')
import os
import shutil
import gzip

OUTPUT_DIR = "build_output{}".format(os.path.sep)

def _get_cpp_define_value(env, define):
define_list = [item[-1] for item in env["CPPDEFINES"] if item[0] == define]

if define_list:
return define_list[0]

return None

def _create_dirs(dirs=["firmware"]):
# check if output directories exist and create if necessary
if not os.path.isdir(OUTPUT_DIR):
os.mkdir(OUTPUT_DIR)

for d in dirs:
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
os.mkdir("{}{}".format(OUTPUT_DIR, d))

def bin_rename_copy(source, target, env):
if not os.path.isdir(OUTPUT_DIR):
os.mkdir(OUTPUT_DIR)
if not os.path.isdir("{}{}".format(OUTPUT_DIR, "firmware")):
os.mkdir("{}{}".format(OUTPUT_DIR, "firmware"))

variant = env["PIOENV"]

# create string with location and file names based on variant
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)

release_name = _get_cpp_define_value(env, "RELEASE_NAME")

if release_name:
_create_dirs(["release"])
release_file = "{}release{}ProjektionFX_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, variant, release_name)
shutil.copy(str(target[0]), release_file)

# check if new target files exist and remove if necessary
for f in [bin_file]:
if os.path.isfile(f):
os.remove(f)

# copy firmware.bin to firmware/<variant>.bin
shutil.copy(str(target[0]), bin_file)

# # copy firmware.map to map/<variant>.map
# if os.path.isfile("firmware.map"):
# shutil.move("firmware.map", map_file)

def bin_gzip(source, target, env):
# _create_dirs()
variant = env["PIOENV"]

# create string with location and file names based on variant
bin_file = "{}firmware{}ProjektionFX_{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)

# check if new target files exist and remove if necessary
if os.path.isfile(gzip_file): os.remove(gzip_file)

# # write gzip firmware file
# with open(bin_file,"rb") as fp:
# with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
# shutil.copyfileobj(fp, f)

env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy, bin_gzip])
15 changes: 12 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,35 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[scripts_defaults]
extra_scripts = post:pio-scripts/rename-releases.py


[env]
framework = arduino
monitor_speed = 115200
upload_speed = 256000
extra_scripts = ${scripts_defaults.extra_scripts}


lib_deps =
fastled/FastLED@^3.5.0
knolleary/PubSubClient@^2.8
bblanchon/ArduinoJson@^6.19.4
https://github.com/tzapu/WiFiManager.git#2.0.3-alpha
https://github.com/tzapu/WiFiManager.git#v2.0.11-beta


[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
build_flags = -D RELEASE_NAME=ESP8266

[env:d1_mini]
board = d1_mini
platform = espressif8266
build_flags = -D RELEASE_NAME=ESP8266

[env:esp32]
[env:esp32thing]
board = esp32thing
platform = espressif32
platform = espressif32 @ 3.0.0
build_flags = -D RELEASE_NAME=ESP32 -D LED_PIN=4
Loading

0 comments on commit 7a93238

Please sign in to comment.