feat: initial commit
Some checks failed
/ platformio (push) Failing after 31s
/ openscad (push) Successful in 1m11s

This commit is contained in:
s3lph 2023-11-20 01:26:48 +01:00
commit 0e674fe5f8
Signed by: s3lph
GPG key ID: 0AA29A52FB33CFB5
10 changed files with 374 additions and 0 deletions

View file

@ -0,0 +1,26 @@
---
on: push
jobs:
platformio:
runs-on: docker
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- run: |
apt update; apt install --yes python3-pip
pip3 install platformio
cd esp
sed -re 's/put your ssid here/"ssid"' -i src/main.cpp
sed -re 's/put your psk here/"psk"' -i src/main.cpp
pio run
openscad:
runs-on: docker
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- run: |
apt update; apt install --yes openscad
cd case
openscad -o pipeline.stl clock.scad

92
README.md Normal file
View file

@ -0,0 +1,92 @@
# Ambient Lighting Clock
3D model and ESP8266 code for a clock that projects colorful rays of light against the wall:
* **Hours**: Wide red
* **Minutes**: Blueish green
* **Seconds**: Blue
## Enclosure
The directory `case` contains the [OpenSCAD](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual) project and rendered STL file of the clock's enclosure.
The enclosure is designed to be 3D-printed, and fits an 60x WS2812 LEDs strip with 144 LEDs per meter, such as [this one (AliExpress link)](https://de.aliexpress.com/item/32682015405.html)
The enclosure also contains mounting holes to which a front plate can be attached (such as in the photo above).
## ESP8266
At the heart of the clock sits an ESP8266, which connects to a WiFi network and fetches the current time of day via NTP.
To build the code and program the ESP, you need to install the [PlatformIO](https://platformio.org/) framework.
```shell-session
$ git clone https://git.kabelsalat.ch/s3lph/ambient-lighting-clock.git
$ cd ambient-lighting-clock/esp
$ vim src/main.cpp # Insert the WiFi SSID and PSK
$ pio run # To download dependencies and build without programming the ESP
Processing main (platform: espressif8266; board: nodemcu; framework: arduino)
--------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/nodemcu.html
PLATFORM: Espressif 8266 (2023.4.0) > NodeMCU 0.9 (ESP-12 Module)
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
PACKAGES:
- framework-arduinoespressif8266 @ 2.7.4+9
- tool-esptoolpy @ 1.40501.0 (4.5.1)
- toolchain-xtensa @ 2.40802.200502 (4.8.2)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 31 compatible libraries
Scanning dependencies...
Dependency Graph
|-- Adafruit NeoPixel @ 1.11.0
|-- NTP @ 1.6.0
|-- ESP8266WiFi @ 1.0
Building in release mode
Retrieving maximum program size .pio/build/main/firmware.elf
Checking size .pio/build/main/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [==== ] 35.4% (used 28984 bytes from 81920 bytes)
Flash: [=== ] 26.8% (used 279396 bytes from 1044464 bytes)
==================================================== [SUCCESS] Took 1.58 seconds ====================================================
$ pio run -t upload # To build the code and program it to the ESP8266
Configuring upload protocol...
AVAILABLE: espota, esptool
CURRENT: upload_protocol = esptool
Looking for upload port...
Auto-detected: /dev/ttyUSB0
Uploading .pio/build/main/firmware.bin
esptool.py v4.6-dev
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 2c:3a:e8:01:23:45
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00045fff...
Compressed 283552 bytes to 208462...
Writing at 0x00000000... (7 %)
Writing at 0x00005b34... (15 %)
Writing at 0x0000b2c4... (23 %)
Writing at 0x00010670... (30 %)
Writing at 0x00015f2e... (38 %)
Writing at 0x0001b0d0... (46 %)
Writing at 0x000200a6... (53 %)
Writing at 0x0002523e... (61 %)
Writing at 0x0002a761... (69 %)
Writing at 0x0002fcd8... (76 %)
Writing at 0x00035551... (84 %)
Writing at 0x0003ac1f... (92 %)
Writing at 0x00041169... (100 %)
Wrote 283552 bytes (208462 compressed) at 0x00000000 in 18.3 seconds (effective 124.1 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
=================================================== [SUCCESS] Took 23.76 seconds ====================================================
```

88
case/clock.scad Normal file
View file

@ -0,0 +1,88 @@
$fn=60;
U=411;
R=U/(2*PI);
H=20;
module frame() {
rotate([0,0,3]) {
difference() {
union() {
// fins
for (i=[0:59]) {
rotate([0,0,6*i]) {
translate([0,R+2,1]) {
cube([1,13,H]);
}
}
}
// base plate
cylinder(h=2, r=R+15);
// back plate
translate([0,0,H-2]) {
cylinder(h=2, r=R);
}
// outer back plate
translate([0,0,H-1]) {
difference() {
cylinder(h=2, r=R+15);
translate([0,0,-1]) {
cylinder(h=4, r=R+10);
}
}
}
// led mounting cylinder
translate([0,0,1]) {
cylinder(h=H, r=R);
}
}
// middle cutout
translate([0,0,-1]) {
cylinder(h=H+1, r=R-3);
}
// frontplate mounting hole
for (i=[0:30:359]) {
rotate([0,0,i-3]) {
translate([0,R+7,-1]) {
cylinder(h=4, r=2);
}
}
}
// cable feed hole
rotate([0,0,-3]) {
translate([0,-R-1.9,2]) {
rotate([0,0,25]) {
cube([20,2,H-2]);
}
}
}
rotate([0,0,-3]) {
// back plate mounting hole
translate([0,R-10,H-3]) {
hull() {
cylinder(h=4, r=2.5);
translate([0,-10,0]) {
cylinder(h=5, r=7.5);
}
}
}
// back plate button holes
translate([20,0,H-1]) {
cylinder(h=4, r=2.5);
}
translate([-20,0,H-1]) {
cylinder(h=4, r=2.5);
}
// cabling holes
translate([0,R+1, H-2]) {
rotate([90,0,0]) {
cylinder(h=5, r=2);
}
}
}
}
}
}
frame();

BIN
case/clock.stl Normal file

Binary file not shown.

1
esp/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.pio

39
esp/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
esp/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

20
esp/platformio.ini Normal file
View file

@ -0,0 +1,20 @@
; 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:main]
platform = espressif8266
board = nodemcu
framework = arduino
upload_protocol = esptool
lib_deps =
adafruit/Adafruit NeoPixel@^1.11.0
sstaub/NTP@^1.6
;board_build.mcu = esp8266
;board_build.f_cpu = 80000000L

51
esp/src/main.cpp Normal file
View file

@ -0,0 +1,51 @@
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTP.h>
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(60, 5, NEO_GRB + NEO_KHZ800);
const char *ssid = put your ssid here;
const char *password = put your psk here;
WiFiUDP wifiUdp;
NTP ntp(wifiUdp);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("Connecting ...");
delay(500);
}
Serial.println("Connected");
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
ntp.begin();
Serial.println("start NTP");
pixels.begin();
}
uint8_t sixtyToPixel(int8_t sixty) {
return (60 - ((sixty+30) % 60)) % 60;
}
void loop() {
delay(1000);
ntp.update();
Serial.println(ntp.formattedTime("%T"));
uint8_t h = sixtyToPixel((ntp.hours() % 12) * 5 + (ntp.minutes() / 12));
uint8_t hl = sixtyToPixel((ntp.hours() % 12) * 5 + (ntp.minutes() / 12) - 1);
uint8_t hr = sixtyToPixel((ntp.hours() % 12) * 5 + (ntp.minutes() / 12) + 1);
uint8_t m = sixtyToPixel(ntp.minutes());
uint8_t s = sixtyToPixel(ntp.seconds());
pixels.clear();
pixels.setPixelColor(hl, pixels.getPixelColor(hl) | 0x00ff0000);
pixels.setPixelColor(h, pixels.getPixelColor(h) | 0x00ff0000);
pixels.setPixelColor(hr, pixels.getPixelColor(hr) | 0x00ff0000);
pixels.setPixelColor(m, pixels.getPixelColor(m) | 0x0000ff60);
pixels.setPixelColor(s, pixels.getPixelColor(s) | 0x000000ff);
pixels.show();
}

11
esp/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