Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
63827d3ab6 | |||
fc868a2d81 | |||
7702398b36 | |||
d9063b606a | |||
99c34d029f | |||
f80c314247 | |||
0a3f747d00 | |||
486a1b9be2 | |||
730cc4338f | |||
88e82797a6 | |||
4c10ee9c1f | |||
5dda0da73e | |||
55defdfeaa | |||
4b0a31a2ed | |||
a2b6f234f1 | |||
585b50d0ba | |||
6c3796c776 | |||
59c9bf4477 | |||
d46b07399f | |||
626877d4ee | |||
c5c7791c33 |
25 changed files with 1158 additions and 194 deletions
136
.forgejo/workflows/push.yaml
Normal file
136
.forgejo/workflows/push.yaml
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
name: "BTClock CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: ghcr.io/catthehacker/ubuntu:js-22.04
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
checks: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
cache: yarn
|
||||||
|
cache-dependency-path: "**/yarn.lock"
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/pip
|
||||||
|
~/.platformio/.cache
|
||||||
|
~/data/node_modules
|
||||||
|
.pio
|
||||||
|
data/node_modules
|
||||||
|
key: ${{ runner.os }}-pio
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
cache: "pip"
|
||||||
|
- name: Get current date
|
||||||
|
id: dateAndTime
|
||||||
|
shell: bash
|
||||||
|
run: echo "dateAndTime=$(date +'%Y-%m-%d-%H:%M')" >> $GITHUB_OUTPUT
|
||||||
|
- name: Install PlatformIO Core
|
||||||
|
shell: bash
|
||||||
|
run: pip install --upgrade platformio
|
||||||
|
- name: Build BTClock firmware
|
||||||
|
shell: bash
|
||||||
|
run: pio run
|
||||||
|
- name: Build BTClock filesystem
|
||||||
|
shell: bash
|
||||||
|
run: pio run --target buildfs
|
||||||
|
- name: Copy bootloader to output folder
|
||||||
|
run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin .pio
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
include-hidden-files: true
|
||||||
|
retention-days: 1
|
||||||
|
name: prepared-outputs
|
||||||
|
path: .pio/**/*.bin
|
||||||
|
merge:
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: ghcr.io/catthehacker/ubuntu:js-22.04
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
checks: write
|
||||||
|
needs: build
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chip:
|
||||||
|
- name: lolin_s2_mini
|
||||||
|
version: esp32s2
|
||||||
|
- name: lolin_s3_mini
|
||||||
|
version: esp32s3
|
||||||
|
- name: orangeclock
|
||||||
|
version: esp32s3
|
||||||
|
epd_variant: [213epd, 29epd]
|
||||||
|
exclude:
|
||||||
|
- chip: { name: orangeclock, version: esp32s3 }
|
||||||
|
epd_variant: 213epd
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: prepared-outputs
|
||||||
|
path: .pio
|
||||||
|
- name: Install esptools.py
|
||||||
|
run: pip install --upgrade esptool
|
||||||
|
- name: Create merged firmware binary
|
||||||
|
run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin
|
||||||
|
|
||||||
|
- name: Create checksum for firmware
|
||||||
|
shell: bash
|
||||||
|
run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256
|
||||||
|
|
||||||
|
- name: Create checksum for merged binary
|
||||||
|
run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.sha256
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-${{ matrix.chip.name }}-${{ matrix.epd_variant }}
|
||||||
|
path: |
|
||||||
|
${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin
|
||||||
|
${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.sha256
|
||||||
|
release:
|
||||||
|
runs-on: docker
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
checks: write
|
||||||
|
needs: merge
|
||||||
|
steps:
|
||||||
|
- name: Download matrix outputs
|
||||||
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
||||||
|
with:
|
||||||
|
pattern: build-*
|
||||||
|
merge-multiple: false
|
||||||
|
path: temp
|
||||||
|
- name: Copy files
|
||||||
|
run: |
|
||||||
|
mkdir -p release
|
||||||
|
find temp -type f \( -name "*.bin" -o -name "*.sha256" \) -exec cp -f {} release/ \;
|
||||||
|
- name: Create release
|
||||||
|
uses: https://code.forgejo.org/actions/forgejo-release@v2.4.0
|
||||||
|
with:
|
||||||
|
url: "https://git.btclock.dev"
|
||||||
|
repo: "${{ github.repository }}"
|
||||||
|
direction: upload
|
||||||
|
tag: "${{ github.ref_name }}"
|
||||||
|
sha: "${{ github.sha }}"
|
||||||
|
release-dir: release
|
||||||
|
token: ${{ secrets.TOKEN }}
|
||||||
|
override: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }}
|
||||||
|
prerelease: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }}
|
||||||
|
release-notes-assistant: false
|
10
.github/actions/install-build/action.yml
vendored
10
.github/actions/install-build/action.yml
vendored
|
@ -4,11 +4,11 @@ description: "Install and build"
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
# - uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
# with:
|
with:
|
||||||
# node-version: lts/*
|
node-version: lts/*
|
||||||
# cache: yarn
|
cache: yarn
|
||||||
# cache-dependency-path: '**/yarn.lock'
|
cache-dependency-path: '**/yarn.lock'
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|
22
.github/workflows/tagging.yml
vendored
22
.github/workflows/tagging.yml
vendored
|
@ -23,20 +23,25 @@ jobs:
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: build-outputs
|
name: prepared-outputs
|
||||||
path: .pio/**/*.bin
|
path: .pio/**/*.bin
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: prepare
|
needs: prepare
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
epd_variant: [213epd, 29epd]
|
|
||||||
chip:
|
chip:
|
||||||
- name: lolin_s2_mini
|
- name: lolin_s2_mini
|
||||||
version: esp32s2
|
version: esp32s2
|
||||||
# chips:
|
- name: lolin_s3_mini
|
||||||
# - name: lolin_s3_mini
|
version: esp32s3
|
||||||
# version: esp32s3
|
- name: orangeclock
|
||||||
|
version: esp32s3
|
||||||
|
epd_variant: [213epd, 29epd]
|
||||||
|
exclude:
|
||||||
|
- chip: orangeclock
|
||||||
|
epd_variant: 213epd
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
@ -44,7 +49,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-outputs
|
name: prepared-outputs
|
||||||
path: .pio
|
path: .pio
|
||||||
- name: Install esptools.py
|
- name: Install esptools.py
|
||||||
run: pip install --upgrade esptool
|
run: pip install --upgrade esptool
|
||||||
|
@ -80,11 +85,12 @@ jobs:
|
||||||
- name: Download matrix outputs
|
- name: Download matrix outputs
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-*
|
pattern: build-*
|
||||||
|
merge-multiple: true
|
||||||
- name: Create release
|
- name: Create release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
artifacts: "*/*.bin,*/*.sha256"
|
artifacts: "**/*.bin,**/*.sha256"
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
removeArtifacts: true
|
removeArtifacts: true
|
||||||
makeLatest: true
|
makeLatest: true
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "data"]
|
||||||
|
path = data
|
||||||
|
url = https://git.btclock.dev/btclock/oc-webui.git
|
13
README.md
Normal file
13
README.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# OrangeBTClock (working title)
|
||||||
|
|
||||||
|
[](https://github.com/btclock/OrangeBTClock/actions/workflows/tagging.yml)
|
||||||
|
|
||||||
|
Firmware for cheap ESP32-S2/S3 hardware combined with a eInk display
|
||||||
|
|
||||||
|
See releases for prebuilt binaries, ready to flash (e.g. with the [esphome web flasher](https://web.esphome.io/))
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
- [PlatformIO](https://platformio.org/platformio-ide).
|
||||||
|
- [Node.js](https://nodejs.org/en) and [yarn](https://yarnpkg.com/).
|
||||||
|
|
62
boards/orangeclock.json
Normal file
62
boards/orangeclock.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino":{
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"partitions": "default_8MB.csv",
|
||||||
|
"memory_type": "qio_opi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_ORANGECLOCK",
|
||||||
|
"-DARDUINO_ESP32S3_DEV",
|
||||||
|
"-DIS_ORANGECLOCK",
|
||||||
|
"-DARDUINO_USB_MODE=0",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"psram_type": "opi",
|
||||||
|
"espidf": {
|
||||||
|
"sdkconfig_path": "boards"
|
||||||
|
},
|
||||||
|
"hwids": [
|
||||||
|
[
|
||||||
|
"0x303A",
|
||||||
|
"0x1001"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "esp32s3"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"bluetooth",
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"default_tool": "esp-builtin",
|
||||||
|
"onboard_tools": [
|
||||||
|
"esp-builtin"
|
||||||
|
],
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "OrangeClock",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "8MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"url": "http://github.com/btclock",
|
||||||
|
"vendor": "BTClock"
|
||||||
|
}
|
1
data
Submodule
1
data
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8332fec4a1ec0045d91f063617bb441914e7b67a
|
|
@ -9,24 +9,27 @@
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
data_dir = data/build
|
data_dir = data/build_gz
|
||||||
default_envs = lolin_s2_mini_213epd, lolin_s2_mini_29epd, lolin_s3_mini_213epd
|
default_envs = lolin_s2_mini_213epd, lolin_s2_mini_29epd, lolin_s3_mini_213epd, lolin_s3_mini_29epd, orangeclock_29epd
|
||||||
|
|
||||||
[btclock_base]
|
[btclock_base]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
platform_packages = platformio/framework-arduinoespressif32
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = esp32_exception_decoder, colorize
|
monitor_filters = esp32_exception_decoder, colorize
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
board_build.partitions = partition.csv
|
board_build.partitions = partition.csv
|
||||||
|
extra_scripts = post:scripts/extra_script.py
|
||||||
build_flags =
|
build_flags =
|
||||||
|
!python scripts/git_rev.py
|
||||||
|
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||||
lib_deps =
|
lib_deps =
|
||||||
zinggjm/GxEPD2@^1.5.6
|
zinggjm/GxEPD2@^1.6.1
|
||||||
https://github.com/tzapu/WiFiManager.git#v2.0.17
|
https://github.com/tzapu/WiFiManager.git#v2.0.17
|
||||||
bblanchon/ArduinoJson@^7.0.3
|
bblanchon/ArduinoJson@^7.2.1
|
||||||
mathieucarbou/ESP Async WebServer
|
mathieucarbou/ESP Async WebServer@^3.0.6
|
||||||
gilmaimon/ArduinoWebsockets@^0.5.3
|
fastled/FastLED@^3.9.6
|
||||||
|
|
||||||
[env:lolin_s2_mini]
|
[env:lolin_s2_mini]
|
||||||
extends = btclock_base
|
extends = btclock_base
|
||||||
board = lolin_s2_mini
|
board = lolin_s2_mini
|
||||||
|
@ -58,3 +61,14 @@ extends = env:lolin_s3_mini
|
||||||
build_flags =
|
build_flags =
|
||||||
${btclock_base.build_flags}
|
${btclock_base.build_flags}
|
||||||
-D VERSION_EPD_2_9
|
-D VERSION_EPD_2_9
|
||||||
|
|
||||||
|
|
||||||
|
[env:orangeclock_29epd]
|
||||||
|
extends = btclock_base
|
||||||
|
board = orangeclock
|
||||||
|
build_flags =
|
||||||
|
${btclock_base.build_flags}
|
||||||
|
-D VERSION_EPD_2_9
|
||||||
|
-D IS_ORANGECLOCK
|
||||||
|
-D BUTTON_PIN=45
|
||||||
|
-D NUM_LEDS=2
|
38
scripts/extra_script.py
Normal file
38
scripts/extra_script.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
Import("env")
|
||||||
|
import os
|
||||||
|
import gzip
|
||||||
|
from shutil import copyfileobj, rmtree
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def gzip_file(input_file, output_file):
|
||||||
|
with open(input_file, 'rb') as f_in:
|
||||||
|
with gzip.open(output_file, 'wb') as f_out:
|
||||||
|
copyfileobj(f_in, f_out)
|
||||||
|
|
||||||
|
def process_directory(input_dir, output_dir):
|
||||||
|
if os.path.exists(output_dir):
|
||||||
|
rmtree(output_dir)
|
||||||
|
for root, dirs, files in os.walk(input_dir):
|
||||||
|
relative_path = os.path.relpath(root, input_dir)
|
||||||
|
output_root = os.path.join(output_dir, relative_path)
|
||||||
|
|
||||||
|
Path(output_root).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
# if file.endswith(('.html', '.css', '.js')):
|
||||||
|
input_file_path = os.path.join(root, file)
|
||||||
|
output_file_path = os.path.join(output_root, file + '.gz')
|
||||||
|
gzip_file(input_file_path, output_file_path)
|
||||||
|
print(f'Compressed: {input_file_path} -> {output_file_path}')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Build web interface before building FS
|
||||||
|
def before_buildfs(source, target, env):
|
||||||
|
env.Execute("cd data && yarn && yarn postinstall && yarn build")
|
||||||
|
input_directory = 'data/dist'
|
||||||
|
output_directory = 'data/build_gz'
|
||||||
|
process_directory(input_directory, output_directory)
|
||||||
|
|
||||||
|
os.environ["PUBLIC_BASE_URL"] = ""
|
||||||
|
env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs)
|
8
scripts/git_rev.py
Normal file
8
scripts/git_rev.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
revision = (
|
||||||
|
subprocess.check_output(["git", "rev-parse", "HEAD"])
|
||||||
|
.strip()
|
||||||
|
.decode("utf-8")
|
||||||
|
)
|
||||||
|
print("'-DGIT_REV=\"%s\"'" % revision)
|
81
src/bitmap.hpp
Normal file
81
src/bitmap.hpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pgmspace.h>
|
||||||
|
// 'oclogo', 250x37px
|
||||||
|
const unsigned char epd_bitmap_oclogo [] PROGMEM = {
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x7f, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xfc, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0xf0, 0x0c, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x03, 0xe3, 0x9c, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0xc7, 0x9c, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x0f, 0x8f, 0x9c, 0x01, 0xe0, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x0f, 0x07, 0x9c, 0x00, 0xf0, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x1e, 0x63, 0x9c, 0x00, 0x78, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x1e, 0x71, 0x9c, 0x00, 0x78, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x3c, 0xf8, 0x9c, 0x00, 0x38, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
|
||||||
|
0x3c, 0xfc, 0x1c, 0x00, 0x3c, 0x01, 0xfc, 0x1f, 0xe1, 0xf3, 0xc3, 0xfc, 0x03, 0xe7, 0xe0, 0x03,
|
||||||
|
0xf3, 0xe0, 0x1f, 0xc0, 0x3f, 0xc1, 0xf0, 0xf8, 0x07, 0xf0, 0x00, 0x7f, 0x03, 0xf0, 0x7e, 0x00,
|
||||||
|
0x39, 0xfe, 0x1c, 0x00, 0x1c, 0x03, 0xf8, 0x07, 0xe1, 0xff, 0xdf, 0xff, 0x03, 0xff, 0xf0, 0x0f,
|
||||||
|
0xff, 0xe0, 0x7f, 0xf0, 0x3f, 0x80, 0x40, 0xf8, 0x1f, 0xfc, 0x01, 0xff, 0xc3, 0xf0, 0xfe, 0x00,
|
||||||
|
0x39, 0xff, 0x1c, 0x00, 0x1c, 0x03, 0xf0, 0x07, 0xf1, 0xff, 0xdf, 0xff, 0x83, 0xff, 0xf8, 0x1f,
|
||||||
|
0xff, 0xe0, 0xff, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0xff, 0x03, 0xff, 0xe3, 0xf1, 0xfc, 0x00,
|
||||||
|
0x39, 0xff, 0x9c, 0x00, 0x1c, 0x03, 0xf0, 0x03, 0xf1, 0xff, 0xcf, 0xff, 0x83, 0xff, 0xfc, 0x3f,
|
||||||
|
0xff, 0xe1, 0xff, 0xfc, 0x7e, 0x00, 0x00, 0xf8, 0x7f, 0xff, 0x07, 0xff, 0xf3, 0xf3, 0xf8, 0x00,
|
||||||
|
0x78, 0x00, 0x1c, 0x00, 0x1c, 0x07, 0xe0, 0x03, 0xf1, 0xff, 0xce, 0x1f, 0xc3, 0xff, 0xfc, 0x3f,
|
||||||
|
0x8f, 0xe1, 0xf8, 0x7e, 0x7e, 0x00, 0x00, 0xf8, 0x7f, 0x3f, 0x8f, 0xe3, 0xe3, 0xf7, 0xf0, 0x00,
|
||||||
|
0x78, 0x00, 0x1e, 0x00, 0x1c, 0x07, 0xe0, 0x03, 0xf1, 0xfc, 0x00, 0x0f, 0xc3, 0xf0, 0xfc, 0x7f,
|
||||||
|
0x07, 0xe3, 0xf0, 0x3e, 0x7e, 0x00, 0x00, 0xf8, 0xfc, 0x1f, 0x8f, 0xc1, 0xc3, 0xff, 0xe0, 0x00,
|
||||||
|
0x78, 0x00, 0x1f, 0x00, 0x1c, 0x07, 0xe0, 0x03, 0xf1, 0xf8, 0x00, 0x0f, 0xc3, 0xe0, 0x7c, 0x7e,
|
||||||
|
0x03, 0xe3, 0xf0, 0x3e, 0x7e, 0x00, 0x00, 0xf8, 0xfc, 0x0f, 0xcf, 0x80, 0x03, 0xff, 0xc0, 0x00,
|
||||||
|
0x39, 0xff, 0x0f, 0x80, 0x1c, 0x07, 0xe0, 0x03, 0xf1, 0xf8, 0x07, 0xff, 0xc3, 0xe0, 0x7e, 0x7e,
|
||||||
|
0x03, 0xe3, 0xff, 0xfe, 0x7e, 0x00, 0x00, 0xf8, 0xfc, 0x0f, 0xdf, 0x80, 0x03, 0xff, 0xc0, 0x00,
|
||||||
|
0x39, 0xff, 0x07, 0xc0, 0x1c, 0x03, 0xf0, 0x03, 0xf1, 0xf8, 0x1f, 0xff, 0xc3, 0xe0, 0x7e, 0x7e,
|
||||||
|
0x03, 0xe3, 0xff, 0xfe, 0x7f, 0x00, 0x00, 0xf8, 0xf8, 0x0f, 0xdf, 0x80, 0x03, 0xff, 0xe0, 0x00,
|
||||||
|
0x39, 0xfe, 0x23, 0xe0, 0x1c, 0x03, 0xf0, 0x07, 0xf1, 0xf8, 0x1f, 0xff, 0xc3, 0xe0, 0x7e, 0x7f,
|
||||||
|
0x07, 0xe3, 0xf0, 0x00, 0x3f, 0x00, 0x40, 0xf8, 0xfc, 0x0f, 0xcf, 0x80, 0x03, 0xff, 0xe0, 0x00,
|
||||||
|
0x3c, 0xfc, 0x61, 0xf0, 0x3c, 0x03, 0xf8, 0x0f, 0xe1, 0xf8, 0x3f, 0x0f, 0xc3, 0xe0, 0x7e, 0x3f,
|
||||||
|
0x8f, 0xe3, 0xf0, 0x00, 0x3f, 0x80, 0xe0, 0xf8, 0xfc, 0x1f, 0x8f, 0xc1, 0x83, 0xff, 0xf0, 0x00,
|
||||||
|
0x3c, 0xf8, 0xe0, 0xf8, 0x38, 0x01, 0xff, 0x3f, 0xe1, 0xf8, 0x3f, 0x0f, 0xc3, 0xe0, 0x7e, 0x3f,
|
||||||
|
0xff, 0xe1, 0xf8, 0x30, 0x1f, 0xe3, 0xf0, 0xf8, 0x7e, 0x3f, 0x8f, 0xe3, 0xe3, 0xf3, 0xf8, 0x00,
|
||||||
|
0x1e, 0x71, 0xe4, 0x7c, 0x78, 0x00, 0xff, 0xff, 0xc1, 0xf8, 0x3f, 0x1f, 0xc3, 0xe0, 0x7e, 0x1f,
|
||||||
|
0xff, 0xe1, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0xf8, 0x7f, 0xff, 0x87, 0xff, 0xf3, 0xf1, 0xfc, 0x00,
|
||||||
|
0x1e, 0x43, 0xe6, 0x3c, 0x78, 0x00, 0x7f, 0xff, 0x81, 0xf8, 0x1f, 0xff, 0xc3, 0xe0, 0x7e, 0x0f,
|
||||||
|
0xff, 0xe0, 0xff, 0xfc, 0x0f, 0xff, 0xf0, 0xf8, 0x3f, 0xff, 0x03, 0xff, 0xe3, 0xf0, 0xfe, 0x00,
|
||||||
|
0x0f, 0x07, 0xe7, 0x1c, 0xf0, 0x00, 0x3f, 0xff, 0x01, 0xf8, 0x1f, 0xff, 0xc3, 0xe0, 0x7e, 0x03,
|
||||||
|
0xf3, 0xe0, 0x7f, 0xf8, 0x03, 0xff, 0xe0, 0xf8, 0x1f, 0xfe, 0x01, 0xff, 0xc3, 0xf0, 0x7e, 0x00,
|
||||||
|
0x0f, 0x8f, 0xe7, 0x81, 0xe0, 0x00, 0x0f, 0xfc, 0x01, 0xf8, 0x07, 0xe7, 0xc3, 0xe0, 0x7e, 0x00,
|
||||||
|
0x03, 0xe0, 0x1f, 0xf0, 0x01, 0xff, 0x80, 0xf8, 0x07, 0xf8, 0x00, 0x7f, 0x83, 0xf0, 0x7f, 0x00,
|
||||||
|
0x07, 0xc7, 0xe7, 0xe3, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||||
|
0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x03, 0xe3, 0xe7, 0x87, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
|
||||||
|
0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0xf0, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
|
||||||
|
0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xfc, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||||
|
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x7f, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
|
||||||
|
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
|
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
165
src/config.cpp
165
src/config.cpp
|
@ -3,8 +3,12 @@
|
||||||
Preferences preferences;
|
Preferences preferences;
|
||||||
|
|
||||||
const char *ntpServer = "pool.ntp.org";
|
const char *ntpServer = "pool.ntp.org";
|
||||||
const long gmtOffset_sec = 0;
|
// const long gmtOffset_sec = 0;
|
||||||
const int daylightOffset_sec = 3600;
|
const int daylightOffset_sec = 3600;
|
||||||
|
TaskHandle_t OTAHandle = NULL;
|
||||||
|
SemaphoreHandle_t xButtonSemaphore = NULL;
|
||||||
|
const TickType_t debounceDelay = pdMS_TO_TICKS(500);
|
||||||
|
TickType_t lastButtonPressTime = 0;
|
||||||
|
|
||||||
#define STA_SSID ""
|
#define STA_SSID ""
|
||||||
#define STA_PASS ""
|
#define STA_PASS ""
|
||||||
|
@ -13,7 +17,7 @@ bool isUpdating = false;
|
||||||
|
|
||||||
void setupTime()
|
void setupTime()
|
||||||
{
|
{
|
||||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
configTime(preferences.getInt(SETTING_TIME_OFFSET_MIN), daylightOffset_sec, ntpServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupPreferences()
|
void setupPreferences()
|
||||||
|
@ -37,16 +41,60 @@ void setupPreferences()
|
||||||
{
|
{
|
||||||
preferences.putString(SETTING_CURRENCY, CURRENCY_USD);
|
preferences.putString(SETTING_CURRENCY, CURRENCY_USD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_HOSTNAME_PREFIX))
|
||||||
|
{
|
||||||
|
preferences.putString(SETTING_HOSTNAME_PREFIX, "oc");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_MEMPOOL_INSTANCE))
|
||||||
|
{
|
||||||
|
preferences.putString(SETTING_MEMPOOL_INSTANCE, "https://mempool.space");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_TIME_FORMAT))
|
||||||
|
{
|
||||||
|
preferences.putString(SETTING_TIME_FORMAT, "%H:%M:%S");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_DATE_FORMAT))
|
||||||
|
{
|
||||||
|
preferences.putString(SETTING_DATE_FORMAT, "%d-%m-%Y");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_DECIMAL_SEPARATOR))
|
||||||
|
{
|
||||||
|
preferences.putChar(SETTING_DECIMAL_SEPARATOR, '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_POWER_SAVE_MODE))
|
||||||
|
{
|
||||||
|
preferences.putBool(SETTING_POWER_SAVE_MODE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.isKey(SETTING_TIME_OFFSET_MIN))
|
||||||
|
{
|
||||||
|
preferences.putInt(SETTING_TIME_OFFSET_MIN, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWifi()
|
void setupWifi()
|
||||||
{
|
{
|
||||||
|
uint8_t mac[6];
|
||||||
|
WiFi.macAddress(mac);
|
||||||
|
unsigned long seed = 0;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
seed += (unsigned long)mac[i] << ((i & 1) * 8);
|
||||||
|
}
|
||||||
|
randomSeed(seed);
|
||||||
|
|
||||||
// WiFi.begin(, ");
|
// WiFi.begin(, ");
|
||||||
WiFi.setAutoConnect(true);
|
|
||||||
WiFi.setAutoReconnect(true);
|
WiFi.setAutoReconnect(true);
|
||||||
|
|
||||||
WiFiManager wm;
|
WiFiManager wm;
|
||||||
|
|
||||||
|
#ifndef ARDUINO_ORANGECLOCK
|
||||||
// Touch pin 14 to reset
|
// Touch pin 14 to reset
|
||||||
if (touchRead(14) > 9000)
|
if (touchRead(14) > 9000)
|
||||||
{
|
{
|
||||||
|
@ -63,16 +111,12 @@ void setupWifi()
|
||||||
wm.resetSettings();
|
wm.resetSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
byte mac[6];
|
|
||||||
WiFi.macAddress(mac);
|
|
||||||
String softAP_SSID =
|
String softAP_SSID =
|
||||||
String("OrangeBTClock");
|
String("OrangeBTClock");
|
||||||
WiFi.setHostname(softAP_SSID.c_str());
|
WiFi.setHostname(softAP_SSID.c_str());
|
||||||
String softAP_password =
|
String softAP_password = getAPPassword();
|
||||||
base64::encode(String(mac[2], 16) + String(mac[4], 16) +
|
|
||||||
String(mac[5], 16) + String(mac[1], 16))
|
|
||||||
.substring(2, 10);
|
|
||||||
|
|
||||||
// wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
|
// wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
|
||||||
wm.setWiFiAutoReconnect(false);
|
wm.setWiFiAutoReconnect(false);
|
||||||
|
@ -109,6 +153,7 @@ void setupWifi()
|
||||||
Serial.println("WiFi connected");
|
Serial.println("WiFi connected");
|
||||||
Serial.println("IP address: ");
|
Serial.println("IP address: ");
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
|
epdShowIp();
|
||||||
// WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
// WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||||
// enableWiFi();
|
// enableWiFi();
|
||||||
}
|
}
|
||||||
|
@ -135,7 +180,6 @@ void wakeModemSleep()
|
||||||
|
|
||||||
void enableWiFi()
|
void enableWiFi()
|
||||||
{
|
{
|
||||||
adc_power_on();
|
|
||||||
delay(200);
|
delay(200);
|
||||||
|
|
||||||
WiFi.disconnect(false); // Reconnect the network
|
WiFi.disconnect(false); // Reconnect the network
|
||||||
|
@ -160,7 +204,6 @@ void enableWiFi()
|
||||||
|
|
||||||
void disableWiFi()
|
void disableWiFi()
|
||||||
{
|
{
|
||||||
adc_power_off();
|
|
||||||
WiFi.disconnect(true); // Disconnect from the network
|
WiFi.disconnect(true); // Disconnect from the network
|
||||||
WiFi.mode(WIFI_OFF); // Switch WiFi off
|
WiFi.mode(WIFI_OFF); // Switch WiFi off
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
|
@ -201,4 +244,104 @@ void setupOTA()
|
||||||
else if (error == OTA_END_ERROR) Serial.println("End Failed"); });
|
else if (error == OTA_END_ERROR) Serial.println("End Failed"); });
|
||||||
|
|
||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(
|
||||||
|
OTAUpdateTask, // Task function
|
||||||
|
"OTAUpdateTask", // Task name
|
||||||
|
4096, // Stack size
|
||||||
|
NULL, // Task parameters
|
||||||
|
1, // Priority (higher value means higher priority)
|
||||||
|
&OTAHandle, // Task handle
|
||||||
|
0 // Core to run the task (0 or 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OTAUpdateTask(void *pvParameters)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ArduinoOTA.handle(); // Handle OTA updates
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay to avoid high CPU usage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleButtonTask(void *pvParameters)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (xSemaphoreTake(xButtonSemaphore, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
TickType_t currentTime = xTaskGetTickCount();
|
||||||
|
if ((currentTime - lastButtonPressTime) >= debounceDelay)
|
||||||
|
{
|
||||||
|
lastButtonPressTime = currentTime;
|
||||||
|
|
||||||
|
Serial.println("Button Pressed");
|
||||||
|
|
||||||
|
#ifdef NUM_LEDS
|
||||||
|
leds[0] = CRGB::SkyBlue;
|
||||||
|
leds[1] = CRGB::Black;
|
||||||
|
|
||||||
|
FastLED.show();
|
||||||
|
|
||||||
|
vTaskDelay(100);
|
||||||
|
|
||||||
|
leds[0] = CRGB::Black;
|
||||||
|
leds[1] = CRGB::DarkOrange;
|
||||||
|
|
||||||
|
FastLED.show();
|
||||||
|
|
||||||
|
vTaskDelay(100);
|
||||||
|
|
||||||
|
leds[0] = CRGB::Black;
|
||||||
|
leds[1] = CRGB::Black;
|
||||||
|
|
||||||
|
FastLED.show();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char getCurrencyIcon()
|
||||||
|
{
|
||||||
|
char ret;
|
||||||
|
String currency = preferences.getString(SETTING_CURRENCY);
|
||||||
|
if (currency.equals(CURRENCY_USD))
|
||||||
|
{
|
||||||
|
ret = ICON_DOLLAR;
|
||||||
|
}
|
||||||
|
else if (currency.equals(CURRENCY_EUR))
|
||||||
|
{
|
||||||
|
ret = ICON_EURO;
|
||||||
|
}
|
||||||
|
else if (currency.equals(CURRENCY_GBP))
|
||||||
|
{
|
||||||
|
ret = ICON_POUND;
|
||||||
|
}
|
||||||
|
else if (currency.equals(CURRENCY_JPY))
|
||||||
|
{
|
||||||
|
ret = ICON_YEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR onButtonPress()
|
||||||
|
{
|
||||||
|
xSemaphoreGiveFromISR(xButtonSemaphore, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupButtonISR()
|
||||||
|
{
|
||||||
|
xButtonSemaphore = xSemaphoreCreateBinary();
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(
|
||||||
|
HandleButtonTask, // Task function
|
||||||
|
"Button Task", // Task name
|
||||||
|
2048, // Stack size (bytes)
|
||||||
|
NULL, // Task parameters
|
||||||
|
1, // Priority (1 is default)
|
||||||
|
NULL, // Task handle
|
||||||
|
0); // Core to run the task (0 or 1)
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
#include "driver/adc.h"
|
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
#include <base64.h>
|
#include <base64.h>
|
||||||
#include "epd.hpp"
|
#include "epd.hpp"
|
||||||
|
@ -15,7 +14,12 @@ void setupTime();
|
||||||
void setupPreferences();
|
void setupPreferences();
|
||||||
void setupWifi();
|
void setupWifi();
|
||||||
void setupOTA();
|
void setupOTA();
|
||||||
|
void OTAUpdateTask(void *pvParameters);
|
||||||
|
|
||||||
void wakeModemSleep();
|
void wakeModemSleep();
|
||||||
void setModemSleep();
|
void setModemSleep();
|
||||||
|
|
||||||
bool inPowerSaveMode();
|
bool inPowerSaveMode();
|
||||||
|
char getCurrencyIcon();
|
||||||
|
void IRAM_ATTR onButtonPress();
|
||||||
|
void setupButtonISR();
|
125
src/data.cpp
125
src/data.cpp
|
@ -1,10 +1,11 @@
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
|
|
||||||
const String mempoolInstance = "https://mempool.space";
|
//const String mempoolInstance = "https://mempool.space";
|
||||||
|
|
||||||
const String mempoolPriceApiUrl = mempoolInstance + "/api/v1/prices";
|
const String mempoolPriceApi = "/api/v1/prices";
|
||||||
const String mempoolBlockApiUrl = mempoolInstance + "/api/blocks/tip/height";
|
const String mempoolBlockApi = "/api/blocks/tip/height";
|
||||||
const String mempoolFeeApiUrl = mempoolInstance + "/api/v1/fees/recommended";
|
const String mempoolFeeApi = "/api/v1/fees/recommended";
|
||||||
|
const String mempoolMedianFeeApi = "/api/v1/fees/mempool-blocks";
|
||||||
|
|
||||||
uint lastPrice;
|
uint lastPrice;
|
||||||
uint lastBlock;
|
uint lastBlock;
|
||||||
|
@ -14,7 +15,7 @@ uint getPrice()
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
// Send HTTP request to CoinGecko API
|
// Send HTTP request to CoinGecko API
|
||||||
http.begin(mempoolPriceApiUrl);
|
http.begin(preferences.getString(SETTING_MEMPOOL_INSTANCE) + mempoolPriceApi);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ uint getBlock()
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
// Send HTTP request to CoinGecko API
|
// Send HTTP request to CoinGecko API
|
||||||
http.begin(mempoolBlockApiUrl);
|
http.begin(preferences.getString(SETTING_MEMPOOL_INSTANCE) + mempoolBlockApi);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ String getMempoolFees()
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
// Send HTTP request to CoinGecko API
|
// Send HTTP request to CoinGecko API
|
||||||
http.begin(mempoolFeeApiUrl);
|
http.begin(preferences.getString(SETTING_MEMPOOL_INSTANCE) + mempoolFeeApi);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
|
@ -96,3 +97,113 @@ String getMempoolFees()
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint getMempoolFeesMedian()
|
||||||
|
{
|
||||||
|
HTTPClient http;
|
||||||
|
|
||||||
|
// Send HTTP request to CoinGecko API
|
||||||
|
http.begin(preferences.getString(SETTING_MEMPOOL_INSTANCE) + mempoolMedianFeeApi);
|
||||||
|
|
||||||
|
int httpCode = http.GET();
|
||||||
|
|
||||||
|
if (httpCode == 200)
|
||||||
|
{
|
||||||
|
char feeString[20];
|
||||||
|
String payload = http.getString();
|
||||||
|
JsonDocument doc;
|
||||||
|
deserializeJson(doc, payload);
|
||||||
|
|
||||||
|
snprintf(feeString, 20, "L: %d M: %d H: %d", doc["hourFee"].as<uint>(), doc["halfHourFee"].as<uint>(), doc["fastestFee"].as<uint>());
|
||||||
|
|
||||||
|
return round(doc[0]["medianFee"].as<double>());
|
||||||
|
|
||||||
|
// preferences.putUInt("lastPrice", eurPrice);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.printf("HTTP GET request mempool median fees failed with error: %s\n", http.errorToString(httpCode).c_str());
|
||||||
|
}
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double getSupplyAtBlock(std::uint32_t blockNr)
|
||||||
|
{
|
||||||
|
if (blockNr >= 33 * 210000)
|
||||||
|
{
|
||||||
|
return 20999999.9769;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int initialBlockReward = 50; // Initial block reward
|
||||||
|
const int halvingInterval = 210000; // Number of blocks before halving
|
||||||
|
|
||||||
|
int halvingCount = blockNr / halvingInterval;
|
||||||
|
double totalBitcoinInCirculation = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < halvingCount; ++i)
|
||||||
|
{
|
||||||
|
totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalBitcoinInCirculation += (blockNr % halvingInterval) * initialBlockReward * std::pow(0.5, halvingCount);
|
||||||
|
|
||||||
|
return totalBitcoinInCirculation;
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatNumberWithSuffix(std::uint64_t num, int numCharacters)
|
||||||
|
{
|
||||||
|
static char result[20]; // Adjust size as needed
|
||||||
|
const long long quadrillion = 1000000000000000LL;
|
||||||
|
const long long trillion = 1000000000000LL;
|
||||||
|
const long long billion = 1000000000;
|
||||||
|
const long long million = 1000000;
|
||||||
|
const long long thousand = 1000;
|
||||||
|
|
||||||
|
double numDouble = (double)num;
|
||||||
|
int numDigits = (int)log10(num) + 1;
|
||||||
|
char suffix;
|
||||||
|
|
||||||
|
if (num >= quadrillion || numDigits > 15)
|
||||||
|
{
|
||||||
|
numDouble /= quadrillion;
|
||||||
|
suffix = 'Q';
|
||||||
|
}
|
||||||
|
else if (num >= trillion || numDigits > 12)
|
||||||
|
{
|
||||||
|
numDouble /= trillion;
|
||||||
|
suffix = 'T';
|
||||||
|
}
|
||||||
|
else if (num >= billion || numDigits > 9)
|
||||||
|
{
|
||||||
|
numDouble /= billion;
|
||||||
|
suffix = 'B';
|
||||||
|
}
|
||||||
|
else if (num >= million || numDigits > 6)
|
||||||
|
{
|
||||||
|
numDouble /= million;
|
||||||
|
suffix = 'M';
|
||||||
|
}
|
||||||
|
else if (num >= thousand || numDigits > 3)
|
||||||
|
{
|
||||||
|
numDouble /= thousand;
|
||||||
|
suffix = 'K';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(result, "%llu", (unsigned long long)num);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add suffix
|
||||||
|
int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix);
|
||||||
|
|
||||||
|
// If there's room, add decimal places
|
||||||
|
if (len < numCharacters)
|
||||||
|
{
|
||||||
|
snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -10,3 +10,6 @@
|
||||||
uint getPrice();
|
uint getPrice();
|
||||||
uint getBlock();
|
uint getBlock();
|
||||||
String getMempoolFees();
|
String getMempoolFees();
|
||||||
|
uint getMempoolFeesMedian();
|
||||||
|
double getSupplyAtBlock(std::uint32_t blockNr);
|
||||||
|
String formatNumberWithSuffix(std::uint64_t num, int numCharacters);
|
85
src/epd.cpp
85
src/epd.cpp
|
@ -9,6 +9,10 @@ String currentRow1 = "";
|
||||||
String currentRow2 = "";
|
String currentRow2 = "";
|
||||||
String currentRow3 = "";
|
String currentRow3 = "";
|
||||||
|
|
||||||
|
char currentIcon1;
|
||||||
|
char currentIcon2;
|
||||||
|
char currentIcon3;
|
||||||
|
|
||||||
void setupDisplay()
|
void setupDisplay()
|
||||||
{
|
{
|
||||||
display.init(0, true);
|
display.init(0, true);
|
||||||
|
@ -18,17 +22,26 @@ void setupDisplay()
|
||||||
display.setRotation(1);
|
display.setRotation(1);
|
||||||
display.setFont(&Antonio_SemiBold20pt7b);
|
display.setFont(&Antonio_SemiBold20pt7b);
|
||||||
display.setTextColor(GxEPD_WHITE);
|
display.setTextColor(GxEPD_WHITE);
|
||||||
int16_t tbx, tby;
|
// int16_t tbx, tby;
|
||||||
uint16_t tbw, tbh;
|
// uint16_t tbw, tbh;
|
||||||
display.getTextBounds("OrangeBTClock", 0, 0, &tbx, &tby, &tbw, &tbh);
|
// display.getTextBounds("OrangeBTClock", 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||||
// center the bounding box by transposition of the origin:
|
// // center the bounding box by transposition of the origin:
|
||||||
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
// uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
// uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||||
display.fillScreen(GxEPD_BLACK);
|
display.fillScreen(GxEPD_BLACK);
|
||||||
display.setCursor(x, y);
|
// display.setCursor(x, y);
|
||||||
display.print("OrangeBTClock");
|
// display.print("OrangeBTClock");
|
||||||
|
|
||||||
|
// display.drawImage(epd_bitmap_allArray[0], GxEPD_WHITE, 0,0 250,37);
|
||||||
|
|
||||||
|
int xPos = (display.width() - 250) / 2;
|
||||||
|
int yPos = (display.height() - 37) / 2;
|
||||||
|
display.drawBitmap(xPos,yPos, epd_bitmap_oclogo, 250, 37, GxEPD_WHITE);
|
||||||
display.display(false);
|
display.display(false);
|
||||||
|
|
||||||
|
display.setCursor(0, 37);
|
||||||
|
|
||||||
|
|
||||||
// display.fillScreen(GxEPD_WHITE);
|
// display.fillScreen(GxEPD_WHITE);
|
||||||
// display.drawLine(0, 10, display.width(), 10, GxEPD_BLACK);
|
// display.drawLine(0, 10, display.width(), 10, GxEPD_BLACK);
|
||||||
// display.drawLine(0, row2, display.width(), row2, GxEPD_BLACK);
|
// display.drawLine(0, row2, display.width(), row2, GxEPD_BLACK);
|
||||||
|
@ -43,11 +56,11 @@ void setupDisplay()
|
||||||
|
|
||||||
// display.display(true);
|
// display.display(true);
|
||||||
|
|
||||||
display.setRotation(1);
|
// display.setRotation(1);
|
||||||
// display.fillRect(0, row1, display.width(), 54, GxEPD_BLACK);
|
// // display.fillRect(0, row1, display.width(), 54, GxEPD_BLACK);
|
||||||
display.displayWindow(0, row1, display.width(), row2);
|
// display.displayWindow(0, row1, display.width(), row2);
|
||||||
|
|
||||||
display.display(true);
|
// display.display(false);
|
||||||
|
|
||||||
// display.fillRect(0, row2, display.width(), 54, GxEPD_BLACK);
|
// display.fillRect(0, row2, display.width(), 54, GxEPD_BLACK);
|
||||||
// display.displayWindow(0, row2, display.width(), 54);
|
// display.displayWindow(0, row2, display.width(), 54);
|
||||||
|
@ -60,8 +73,27 @@ void setupDisplay()
|
||||||
// display.display(true);
|
// display.display(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRow2(String c)
|
void epdShowIp() {
|
||||||
|
display.setRotation(1);
|
||||||
|
display.setFont(&LibreFranklin_SemiBold10pt7b);
|
||||||
|
display.setTextColor(GxEPD_WHITE);
|
||||||
|
String ipStr = WiFi.localIP().toString();
|
||||||
|
int16_t tbx, tby;
|
||||||
|
uint16_t tbw, tbh;
|
||||||
|
display.getTextBounds(ipStr, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||||
|
// center the bounding box by transposition of the origin:
|
||||||
|
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||||
|
uint16_t y = ((display.height() - tbh) / 2) - tby + 37;
|
||||||
|
display.setCursor(x, y);
|
||||||
|
display.println(WiFi.localIP());
|
||||||
|
display.display(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateRow2(String c, char icon)
|
||||||
{
|
{
|
||||||
|
if (c.equals(currentRow2) && icon == currentIcon2)
|
||||||
|
return;
|
||||||
|
|
||||||
display.setRotation(1);
|
display.setRotation(1);
|
||||||
display.setFont(&ROW2_FONT);
|
display.setFont(&ROW2_FONT);
|
||||||
display.setTextColor(GxEPD_BLACK);
|
display.setTextColor(GxEPD_BLACK);
|
||||||
|
@ -82,17 +114,23 @@ void updateRow2(String c)
|
||||||
|
|
||||||
display.setFont(&ROW2_ICONFONT);
|
display.setFont(&ROW2_ICONFONT);
|
||||||
display.setCursor(x, y);
|
display.setCursor(x, y);
|
||||||
display.print(ICON_BLOCK);
|
display.print(icon);
|
||||||
|
|
||||||
display.setFont(&ROW2_FONT);
|
display.setFont(&ROW2_FONT);
|
||||||
display.setCursor(x + ROW2_ICONWIDTH, y);
|
display.setCursor(x + ROW2_ICONWIDTH, y);
|
||||||
display.print(c);
|
display.print(c);
|
||||||
} while (display.nextPage());
|
} while (display.nextPage());
|
||||||
// display.display(true);
|
// display.display(true);
|
||||||
|
|
||||||
|
currentRow2 = c;
|
||||||
|
currentIcon2 = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRow3(String c)
|
void updateRow3(String c, char icon)
|
||||||
{
|
{
|
||||||
|
if (c.equals(currentRow3) && icon == currentIcon3)
|
||||||
|
return;
|
||||||
|
|
||||||
display.setRotation(1);
|
display.setRotation(1);
|
||||||
display.setFont(&LibreFranklin_SemiBold15pt7b);
|
display.setFont(&LibreFranklin_SemiBold15pt7b);
|
||||||
display.setTextColor(GxEPD_WHITE);
|
display.setTextColor(GxEPD_WHITE);
|
||||||
|
@ -114,13 +152,16 @@ void updateRow3(String c)
|
||||||
|
|
||||||
display.setFont(&orangeclock_icons15pt7b);
|
display.setFont(&orangeclock_icons15pt7b);
|
||||||
display.setCursor(x, y);
|
display.setCursor(x, y);
|
||||||
display.print(ICON_SATS);
|
display.print(icon);
|
||||||
|
|
||||||
display.setFont(&LibreFranklin_SemiBold15pt7b);
|
display.setFont(&LibreFranklin_SemiBold15pt7b);
|
||||||
|
|
||||||
display.setCursor(x + ROW3_ICONWIDTH, y);
|
display.setCursor(x + ROW3_ICONWIDTH, y);
|
||||||
display.print(c);
|
display.print(c);
|
||||||
} while (display.nextPage());
|
} while (display.nextPage());
|
||||||
|
|
||||||
|
currentRow3 = c;
|
||||||
|
currentIcon3 = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSetupText(String t)
|
void showSetupText(String t)
|
||||||
|
@ -133,7 +174,7 @@ void showSetupText(String t)
|
||||||
// center the bounding box by transposition of the origin:
|
// center the bounding box by transposition of the origin:
|
||||||
uint16_t x = ((display.width() - (tbw)) / 2) - tbx;
|
uint16_t x = ((display.width() - (tbw)) / 2) - tbx;
|
||||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||||
|
display.setFullWindow();
|
||||||
display.firstPage();
|
display.firstPage();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -147,8 +188,11 @@ void showSetupText(String t)
|
||||||
} while (display.nextPage());
|
} while (display.nextPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRow1(String c)
|
void updateRow1(String c, char icon)
|
||||||
{
|
{
|
||||||
|
if (c.equals(currentRow1) && icon == currentIcon1)
|
||||||
|
return;
|
||||||
|
|
||||||
// struct tm timeinfo;
|
// struct tm timeinfo;
|
||||||
// if (!getLocalTime(&timeinfo))
|
// if (!getLocalTime(&timeinfo))
|
||||||
// {
|
// {
|
||||||
|
@ -180,13 +224,16 @@ void updateRow1(String c)
|
||||||
|
|
||||||
display.setFont(&ROW1_ICONFONT);
|
display.setFont(&ROW1_ICONFONT);
|
||||||
display.setCursor(x, y);
|
display.setCursor(x, y);
|
||||||
display.print(ICON_PIE);
|
display.print(icon);
|
||||||
|
|
||||||
display.setFont(&ROW1_FONT);
|
display.setFont(&ROW1_FONT);
|
||||||
|
|
||||||
display.setCursor(x + ROW1_ICONWIDTH, y);
|
display.setCursor(x + ROW1_ICONWIDTH, y);
|
||||||
display.print(c);
|
display.print(c);
|
||||||
} while (display.nextPage());
|
} while (display.nextPage());
|
||||||
|
|
||||||
|
currentRow1 = c;
|
||||||
|
currentIcon1 = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRows(String row1Content, String row2Content, String row3Content)
|
void updateRows(String row1Content, String row2Content, String row3Content)
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
#include "fonts/fonts.hpp"
|
#include "fonts/fonts.hpp"
|
||||||
|
#include "bitmap.hpp"
|
||||||
void setupDisplay();
|
void setupDisplay();
|
||||||
|
|
||||||
void showSetupText(String t);
|
void showSetupText(String t);
|
||||||
void updateRow1(String c);
|
void updateRow1(String c, char icon);
|
||||||
void updateRow2(String c);
|
void updateRow2(String c, char icon);
|
||||||
void updateRow3(String c);
|
void updateRow3(String c, char icon);
|
||||||
void updateRows(String row1Content, String row2Content, String row3Content);
|
void updateRows(String row1Content, String row2Content, String row3Content);
|
||||||
|
void epdShowIp();
|
312
src/main.cpp
312
src/main.cpp
|
@ -21,19 +21,44 @@ GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display = EPD_CLASS(4, 2, 3, 1);
|
||||||
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display = EPD_CLASS(5, 3, 2, 1);
|
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display = EPD_CLASS(5, 3, 2, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WiFiClientSecure client;
|
#ifdef ARDUINO_ORANGECLOCK
|
||||||
|
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display = EPD_CLASS(5, 3, 1, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*MethodPtr)(String, char);
|
||||||
|
|
||||||
|
MethodPtr methods[] = {nullptr, updateRow1, updateRow2, updateRow3};
|
||||||
|
|
||||||
|
WiFiClient client;
|
||||||
uint currentPrice = 0;
|
uint currentPrice = 0;
|
||||||
String currentBlock = "";
|
String currentBlock = "";
|
||||||
String currentFees = "";
|
String currentFees = "";
|
||||||
|
|
||||||
|
#ifdef NUM_LEDS
|
||||||
|
CRGB leds[NUM_LEDS];
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
// setCpuFrequencyMhz(40);
|
// setCpuFrequencyMhz(40);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
#ifndef IS_ORANGECLOCK
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
#else
|
||||||
|
|
||||||
|
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
attachInterrupt(BUTTON_PIN, onButtonPress, FALLING);
|
||||||
|
|
||||||
|
FastLED.addLeds<WS2812B, 48, GRB>(leds, NUM_LEDS);
|
||||||
|
leds[0] = CRGB::GreenYellow;
|
||||||
|
leds[1] = CRGB::OrangeRed;
|
||||||
|
|
||||||
|
FastLED.show();
|
||||||
|
|
||||||
|
setupButtonISR();
|
||||||
|
#endif
|
||||||
|
|
||||||
setupPreferences();
|
setupPreferences();
|
||||||
setupDisplay();
|
setupDisplay();
|
||||||
|
@ -46,15 +71,27 @@ void setup()
|
||||||
setupWebserver();
|
setupWebserver();
|
||||||
setupOTA();
|
setupOTA();
|
||||||
}
|
}
|
||||||
client.setInsecure();
|
// client.setInsecure();
|
||||||
|
|
||||||
|
#ifndef IS_ORANGECLOCK
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#else
|
||||||
|
leds[0] = CRGB::Black;
|
||||||
|
leds[1] = CRGB::Black;
|
||||||
|
|
||||||
|
FastLED.show();
|
||||||
|
delay(100);
|
||||||
|
#endif
|
||||||
|
display.setFullWindow();
|
||||||
|
display.clearScreen(GxEPD_WHITE);
|
||||||
|
display.display(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
if (isUpdating) {
|
if (isUpdating)
|
||||||
ArduinoOTA.handle();
|
{
|
||||||
|
delay(1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,132 +103,203 @@ void loop()
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client.setInsecure();
|
// client.setInsecure();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
IPAddress res;
|
// IPAddress res;
|
||||||
uint result = WiFi.hostByName("mempool.space", res);
|
// uint result = WiFi.hostByName("mempool.space", res);
|
||||||
|
|
||||||
if (result >= 0)
|
// if (result >= 0)
|
||||||
{
|
// {
|
||||||
Serial.print("SUCCESS!");
|
// Serial.print("SUCCESS!");
|
||||||
Serial.println(res.toString());
|
// Serial.println(res.toString());
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
WiFi.reconnect();
|
// WiFi.reconnect();
|
||||||
|
|
||||||
while (WiFi.status() != WL_CONNECTED)
|
// while (WiFi.status() != WL_CONNECTED)
|
||||||
|
// {
|
||||||
|
// Serial.print('.');
|
||||||
|
// delay(1000);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (uint i = 1; i <= 3; i++)
|
||||||
|
{
|
||||||
|
String rowContent = "";
|
||||||
|
char icon;
|
||||||
|
char keyName[5];
|
||||||
|
snprintf(keyName, sizeof(keyName), "row%d", i);
|
||||||
|
switch (preferences.getUInt(keyName))
|
||||||
{
|
{
|
||||||
Serial.print('.');
|
case LINE_BLOCKHEIGHT:
|
||||||
delay(1000);
|
icon = ICON_BLOCK;
|
||||||
}
|
rowContent = getBlock();
|
||||||
}
|
break;
|
||||||
|
case LINE_MEMPOOL_FEES:
|
||||||
String block = String(getBlock());
|
icon = ICON_PIE;
|
||||||
|
rowContent = getMempoolFees();
|
||||||
uint tryCount = 0;
|
break;
|
||||||
while (block.equals(""))
|
case LINE_MEMPOOL_FEES_MEDIAN:
|
||||||
{
|
icon = ICON_PIE;
|
||||||
block = getBlock();
|
rowContent = getMempoolFeesMedian();
|
||||||
Serial.print("Retry block..");
|
break;
|
||||||
tryCount++;
|
case LINE_HALVING_COUNTDOWN:
|
||||||
|
|
||||||
Serial.println(tryCount);
|
|
||||||
delay(1000);
|
|
||||||
|
|
||||||
if (tryCount % 5)
|
|
||||||
{
|
{
|
||||||
WiFi.disconnect();
|
icon = ICON_HOURGLASS;
|
||||||
WiFi.reconnect();
|
uint currentBlock = getBlock();
|
||||||
|
rowContent = 210000 - (currentBlock % 210000);
|
||||||
while (WiFi.status() != WL_CONNECTED)
|
break;
|
||||||
{
|
|
||||||
Serial.print('.');
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case LINE_SATSPERUNIT:
|
||||||
|
{
|
||||||
|
icon = ICON_SATS;
|
||||||
|
uint satsPerDollar = int(round(1 / float(getPrice()) * 10e7));
|
||||||
|
rowContent = satsPerDollar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LINE_FIATPRICE:
|
||||||
|
icon = getCurrencyIcon();
|
||||||
|
rowContent = getPrice();
|
||||||
|
break;
|
||||||
|
case LINE_MARKETCAP:
|
||||||
|
{
|
||||||
|
icon = getCurrencyIcon();
|
||||||
|
int64_t marketCap = static_cast<std::int64_t>(getSupplyAtBlock(getBlock()) * double(getPrice()));
|
||||||
|
rowContent = String(formatNumberWithSuffix(marketCap, 8));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LINE_TIME:
|
||||||
|
{
|
||||||
|
icon = ICON_GLOBE;
|
||||||
|
char dateString[16];
|
||||||
|
strftime(dateString, sizeof(dateString), preferences.getString(SETTING_TIME_FORMAT).c_str(), &timeinfo);
|
||||||
|
rowContent = dateString;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LINE_DATE:
|
||||||
|
{
|
||||||
|
icon = ICON_GLOBE;
|
||||||
|
char dateString[16];
|
||||||
|
strftime(dateString, sizeof(dateString), preferences.getString(SETTING_DATE_FORMAT).c_str(), &timeinfo);
|
||||||
|
rowContent = dateString;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
rowContent = "DEFAULT";
|
||||||
|
}
|
||||||
|
|
||||||
|
methods[i](rowContent, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint price = getPrice();
|
// String block = String(getBlock());
|
||||||
tryCount = 0;
|
|
||||||
while (price == 0)
|
|
||||||
{
|
|
||||||
price = getPrice();
|
|
||||||
if (Serial.available())
|
|
||||||
Serial.print("Retry price..");
|
|
||||||
tryCount++;
|
|
||||||
if (Serial.available())
|
|
||||||
Serial.println(tryCount);
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint satsPerDollar = int(round(1 / float(price) * 10e7));
|
// uint tryCount = 0;
|
||||||
|
// while (block.equals(""))
|
||||||
|
// {
|
||||||
|
// block = getBlock();
|
||||||
|
// Serial.print("Retry block..");
|
||||||
|
// tryCount++;
|
||||||
|
|
||||||
String mempoolFees = getMempoolFees();
|
// Serial.println(tryCount);
|
||||||
tryCount = 0;
|
// delay(1000);
|
||||||
while (mempoolFees.equals(""))
|
|
||||||
{
|
|
||||||
mempoolFees = getMempoolFees();
|
|
||||||
Serial.print("Retry mempoolfees..");
|
|
||||||
tryCount++;
|
|
||||||
|
|
||||||
Serial.println(tryCount);
|
// if (tryCount % 5)
|
||||||
delay(1000);
|
// {
|
||||||
}
|
// WiFi.disconnect();
|
||||||
|
// WiFi.reconnect();
|
||||||
|
|
||||||
if (!currentFees.equals(mempoolFees))
|
// while (WiFi.status() != WL_CONNECTED)
|
||||||
{
|
// {
|
||||||
updateRow1(mempoolFees);
|
// Serial.print('.');
|
||||||
currentFees = mempoolFees;
|
// delay(1000);
|
||||||
Serial.print(F("Fees is now "));
|
// }
|
||||||
Serial.println(currentFees);
|
// }
|
||||||
}
|
// }
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println(F("No need to update fees"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (price != currentPrice)
|
// uint price = getPrice();
|
||||||
{
|
// tryCount = 0;
|
||||||
updateRow3(String(satsPerDollar));
|
// while (price == 0)
|
||||||
currentPrice = price;
|
// {
|
||||||
Serial.print(F("Price is now "));
|
// price = getPrice();
|
||||||
Serial.println(currentPrice);
|
// if (Serial.available())
|
||||||
}
|
// Serial.print("Retry price..");
|
||||||
else
|
// tryCount++;
|
||||||
{
|
// if (Serial.available())
|
||||||
Serial.println(F("No need to update price"));
|
// Serial.println(tryCount);
|
||||||
}
|
// delay(1000);
|
||||||
|
// }
|
||||||
|
|
||||||
if (!block.equals(currentBlock))
|
// uint satsPerDollar = int(round(1 / float(price) * 10e7));
|
||||||
{
|
|
||||||
updateRow2(block);
|
// String mempoolFees = getMempoolFees();
|
||||||
currentBlock = block;
|
// tryCount = 0;
|
||||||
Serial.print(F("Block is now "));
|
// while (mempoolFees.equals(""))
|
||||||
Serial.println(currentBlock);
|
// {
|
||||||
}
|
// mempoolFees = getMempoolFees();
|
||||||
else
|
// Serial.print("Retry mempoolfees..");
|
||||||
{
|
// tryCount++;
|
||||||
Serial.println(F("No need to update block"));
|
|
||||||
}
|
// Serial.println(tryCount);
|
||||||
|
// delay(1000);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!currentFees.equals(mempoolFees))
|
||||||
|
// {
|
||||||
|
// updateRow1(mempoolFees);
|
||||||
|
// currentFees = mempoolFees;
|
||||||
|
// Serial.print(F("Fees is now "));
|
||||||
|
// Serial.println(currentFees);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// Serial.println(F("No need to update fees"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (price != currentPrice)
|
||||||
|
// {
|
||||||
|
// updateRow3(String(satsPerDollar));
|
||||||
|
// currentPrice = price;
|
||||||
|
// Serial.print(F("Price is now "));
|
||||||
|
// Serial.println(currentPrice);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// Serial.println(F("No need to update price"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!block.equals(currentBlock))
|
||||||
|
// {
|
||||||
|
// updateRow2(block);
|
||||||
|
// currentBlock = block;
|
||||||
|
// Serial.print(F("Block is now "));
|
||||||
|
// Serial.println(currentBlock);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// Serial.println(F("No need to update block"));
|
||||||
|
// }
|
||||||
|
|
||||||
// updateRows(mempoolFees, block, String(price));
|
// updateRows(mempoolFees, block, String(price));
|
||||||
|
|
||||||
delay(2 * 1000);
|
delay(2 * 1000);
|
||||||
|
|
||||||
if (inPowerSaveMode()) {
|
if (inPowerSaveMode())
|
||||||
|
{
|
||||||
display.hibernate();
|
display.hibernate();
|
||||||
setModemSleep();
|
setModemSleep();
|
||||||
esp_sleep_enable_timer_wakeup(50 * 1000000);
|
esp_sleep_enable_timer_wakeup(50 * 1000000);
|
||||||
esp_light_sleep_start();
|
esp_light_sleep_start();
|
||||||
display.init(0, false);
|
display.init(0, false);
|
||||||
wakeModemSleep();
|
wakeModemSleep();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Serial.println(F("Sleeping"));
|
Serial.println(F("Sleeping"));
|
||||||
sleep(50);
|
sleep(50);
|
||||||
// delay(50 * 1000);
|
// delay(50 * 1000);
|
||||||
Serial.println(F("Waking up"));
|
Serial.println(F("Waking up"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
src/shared.cpp
Normal file
3
src/shared.cpp
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#include "shared.hpp"
|
||||||
|
|
||||||
|
volatile bool buttonPressed = false;
|
|
@ -1,11 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClient.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <GxEPD2.h>
|
#include <GxEPD2.h>
|
||||||
#include <GxEPD2_BW.h>
|
#include <GxEPD2_BW.h>
|
||||||
|
#include "utils.hpp"
|
||||||
#include "fonts/fonts.hpp"
|
#include "fonts/fonts.hpp"
|
||||||
|
#include <FastLED.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
#ifdef VERSION_EPD_2_13
|
#ifdef VERSION_EPD_2_13
|
||||||
#define EPD_CLASS GxEPD2_213_B74
|
#define EPD_CLASS GxEPD2_213_B74
|
||||||
|
@ -26,40 +31,48 @@
|
||||||
#define EPD_CLASS GxEPD2_290_T94
|
#define EPD_CLASS GxEPD2_290_T94
|
||||||
#define ROW1_FONT LibreFranklin_SemiBold15pt7b
|
#define ROW1_FONT LibreFranklin_SemiBold15pt7b
|
||||||
#define ROW1_ICONFONT orangeclock_icons14pt7b
|
#define ROW1_ICONFONT orangeclock_icons14pt7b
|
||||||
#define ROW1_ICONWIDTH 27
|
#define ROW1_ICONWIDTH 29
|
||||||
#define ROW2_FONT LibreFranklin_Bold25pt7b
|
#define ROW2_FONT LibreFranklin_Bold25pt7b
|
||||||
#define ROW2_ICONFONT orangeclock_icons25pt7b
|
#define ROW2_ICONFONT orangeclock_icons25pt7b
|
||||||
#define ROW2_ICONWIDTH 52
|
#define ROW2_ICONWIDTH 52
|
||||||
#define ROW3_FONT LibreFranklin_SemiBold15pt7b
|
#define ROW3_FONT LibreFranklin_SemiBold15pt7b
|
||||||
#define ROW3_ICONFONT orangeclock_icons14pt7b
|
#define ROW3_ICONFONT orangeclock_icons14pt7b
|
||||||
#define ROW3_ICONWIDTH 27
|
#define ROW3_ICONWIDTH 29
|
||||||
|
|
||||||
#define SETUPFONT LibreFranklin_SemiBold12pt7b
|
#define SETUPFONT LibreFranklin_SemiBold12pt7b
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ICON_BLOCK "A"
|
#define ICON_BLOCK 'A'
|
||||||
#define ICON_EURO "B"
|
#define ICON_EURO 'B'
|
||||||
#define ICON_POUND "C"
|
#define ICON_POUND 'C'
|
||||||
#define ICON_YEN "D"
|
#define ICON_YEN 'D'
|
||||||
#define ICON_DOLLAR "E"
|
#define ICON_DOLLAR 'E'
|
||||||
#define ICON_PIE "F"
|
#define ICON_PIE 'F'
|
||||||
#define ICON_GLOBE "G"
|
#define ICON_GLOBE 'G'
|
||||||
#define ICON_HOURGLASS "H"
|
#define ICON_HOURGLASS 'H'
|
||||||
#define ICON_LIGHTNING "I"
|
#define ICON_LIGHTNING 'I'
|
||||||
#define ICON_REFRESH "J"
|
#define ICON_REFRESH 'J'
|
||||||
#define ICON_NUCLEAR "K"
|
#define ICON_NUCLEAR 'K'
|
||||||
#define ICON_SATS "L"
|
#define ICON_SATS 'L'
|
||||||
#define ICON_SATUSD "M"
|
#define ICON_SATUSD 'M'
|
||||||
#define ICON_SETTINGS "N"
|
#define ICON_SETTINGS 'N'
|
||||||
#define ICON_WIFI "O"
|
#define ICON_WIFI 'O'
|
||||||
#define ICON_CROSS "P"
|
#define ICON_CROSS 'P'
|
||||||
#define ICON_CHECK "Q"
|
#define ICON_CHECK 'Q'
|
||||||
#define ICON_WARNING "R"
|
#define ICON_WARNING 'R'
|
||||||
|
|
||||||
#define SETTING_ROW1_CONTENT "row1"
|
#define SETTING_ROW1_CONTENT "row1"
|
||||||
#define SETTING_ROW2_CONTENT "row2"
|
#define SETTING_ROW2_CONTENT "row2"
|
||||||
#define SETTING_ROW3_CONTENT "row3"
|
#define SETTING_ROW3_CONTENT "row3"
|
||||||
#define SETTING_CURRENCY "currency"
|
#define SETTING_CURRENCY "currency"
|
||||||
|
#define SETTING_HOSTNAME_PREFIX "hostnamePrefix"
|
||||||
|
#define SETTING_MEMPOOL_INSTANCE "mempoolInstance"
|
||||||
|
#define SETTING_POWER_SAVE_MODE "powerSaveMode"
|
||||||
|
#define SETTING_TIME_OFFSET_MIN "timeOffsetMin"
|
||||||
|
#define SETTING_DECIMAL_SEPARATOR "decSeparator"
|
||||||
|
#define SETTING_TIME_FORMAT "timeFormat"
|
||||||
|
#define SETTING_DATE_FORMAT "dateFormat"
|
||||||
|
|
||||||
|
|
||||||
const int LINE_BLOCKHEIGHT = 0;
|
const int LINE_BLOCKHEIGHT = 0;
|
||||||
const int LINE_MEMPOOL_FEES = 1;
|
const int LINE_MEMPOOL_FEES = 1;
|
||||||
|
@ -79,7 +92,20 @@ const int LINE_DATE = 100;
|
||||||
#define CURRENCY_AUD "AUD"
|
#define CURRENCY_AUD "AUD"
|
||||||
#define CURRENCY_JPY "JPY"
|
#define CURRENCY_JPY "JPY"
|
||||||
|
|
||||||
extern WiFiClientSecure client;
|
extern WiFiClient client;
|
||||||
extern GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display;
|
extern GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display;
|
||||||
extern Preferences preferences;
|
extern Preferences preferences;
|
||||||
extern bool isUpdating;
|
extern bool isUpdating;
|
||||||
|
|
||||||
|
extern String currentRow1;
|
||||||
|
extern String currentRow2;
|
||||||
|
extern String currentRow3;
|
||||||
|
|
||||||
|
extern char currentIcon1;
|
||||||
|
extern char currentIcon2;
|
||||||
|
extern char currentIcon3;
|
||||||
|
|
||||||
|
#ifdef NUM_LEDS
|
||||||
|
extern CRGB leds[NUM_LEDS];
|
||||||
|
#endif
|
||||||
|
extern volatile bool buttonPressed;
|
32
src/utils.cpp
Normal file
32
src/utils.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
String getAPPassword()
|
||||||
|
{
|
||||||
|
byte mac[6];
|
||||||
|
WiFi.macAddress(mac);
|
||||||
|
const char charset[] = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
||||||
|
char password[9]; // 8 characters + null terminator
|
||||||
|
snprintf(password, sizeof(password), "%c%c%c%c%c%c%c%c",
|
||||||
|
charset[mac[0] % (sizeof(charset) - 1)],
|
||||||
|
charset[mac[1] % (sizeof(charset) - 1)],
|
||||||
|
charset[mac[2] % (sizeof(charset) - 1)],
|
||||||
|
charset[mac[3] % (sizeof(charset) - 1)],
|
||||||
|
charset[mac[4] % (sizeof(charset) - 1)],
|
||||||
|
charset[mac[5] % (sizeof(charset) - 1)],
|
||||||
|
charset[(mac[0] + mac[1] + mac[2] + mac[3] + mac[4] + mac[5]) % (sizeof(charset) - 1)],
|
||||||
|
charset[(mac[0] * mac[1] * mac[2] * mac[3] * mac[4] * mac[5]) % (sizeof(charset) - 1)]);
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getMyHostname()
|
||||||
|
{
|
||||||
|
uint8_t mac[6];
|
||||||
|
// WiFi.macAddress(mac);
|
||||||
|
esp_efuse_mac_get_default(mac);
|
||||||
|
char hostname[15];
|
||||||
|
String hostnamePrefix = preferences.getString(SETTING_HOSTNAME_PREFIX);
|
||||||
|
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x", hostnamePrefix,
|
||||||
|
mac[3], mac[4], mac[5]);
|
||||||
|
return hostname;
|
||||||
|
}
|
28
src/utils.hpp
Normal file
28
src/utils.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.hpp>
|
||||||
|
#include "shared.hpp"
|
||||||
|
#include <esp_mac.h>
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
template <>
|
||||||
|
struct Converter<char> {
|
||||||
|
static void toJson(char c, JsonVariant var) {
|
||||||
|
var.set(static_cast<signed char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char fromJson(JsonVariantConst src) {
|
||||||
|
return static_cast<char>(src.as<signed char>());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariantConst src) {
|
||||||
|
return src.is<signed char>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String getAPPassword();
|
||||||
|
String getMyHostname();
|
|
@ -3,8 +3,10 @@
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
const String uintSettings[] = {SETTING_ROW1_CONTENT, SETTING_ROW2_CONTENT, SETTING_ROW3_CONTENT};
|
const String uintSettings[] = {SETTING_ROW1_CONTENT, SETTING_ROW2_CONTENT, SETTING_ROW3_CONTENT};
|
||||||
const String stringSettings[] = {SETTING_CURRENCY};
|
const String intSettings[] = {SETTING_TIME_OFFSET_MIN};
|
||||||
const String boolSettings[] = {};
|
const String stringSettings[] = {SETTING_CURRENCY, SETTING_MEMPOOL_INSTANCE, SETTING_TIME_FORMAT, SETTING_DATE_FORMAT};
|
||||||
|
const String charSettings[] = {SETTING_DECIMAL_SEPARATOR};
|
||||||
|
const String boolSettings[] = {SETTING_POWER_SAVE_MODE};
|
||||||
|
|
||||||
void setupWebserver()
|
void setupWebserver()
|
||||||
{
|
{
|
||||||
|
@ -13,14 +15,20 @@ void setupWebserver()
|
||||||
Serial.println(F("An Error has occurred while mounting LittleFS"));
|
Serial.println(F("An Error has occurred while mounting LittleFS"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.on("/api/status", HTTP_GET, onApiStatus);
|
||||||
server.on("/api/settings", HTTP_GET, onApiSettingsGet);
|
server.on("/api/settings", HTTP_GET, onApiSettingsGet);
|
||||||
|
server.on("/api/restart", HTTP_GET, onApiRestart);
|
||||||
|
server.on("/api/full_refresh", HTTP_GET, onApiFullRefresh);
|
||||||
|
|
||||||
AsyncCallbackJsonWebHandler *settingsPatchHandler =
|
AsyncCallbackJsonWebHandler *settingsPatchHandler =
|
||||||
new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch);
|
new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch);
|
||||||
server.addHandler(settingsPatchHandler);
|
server.addHandler(settingsPatchHandler);
|
||||||
|
|
||||||
server.serveStatic("/build", LittleFS, "/build");
|
server.serveStatic("/build", LittleFS, "/build");
|
||||||
|
server.serveStatic("/fonts", LittleFS, "/fonts");
|
||||||
|
|
||||||
server.on("/", HTTP_GET, onIndex);
|
server.on("/", HTTP_GET, onIndex);
|
||||||
|
server.onNotFound(onNotFound);
|
||||||
|
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods",
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods",
|
||||||
|
@ -30,6 +38,31 @@ void setupWebserver()
|
||||||
server.begin();
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onApiStatus(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
JsonDocument root;
|
||||||
|
|
||||||
|
root["row1"] = currentRow1;
|
||||||
|
root["row2"] = currentRow2;
|
||||||
|
root["row3"] = currentRow3;
|
||||||
|
|
||||||
|
root["icon1"] = String(currentIcon1);
|
||||||
|
root["icon2"] = String(currentIcon2);
|
||||||
|
root["icon3"] = String(currentIcon3);
|
||||||
|
|
||||||
|
root["espUptime"] = esp_timer_get_time() / 1000000;
|
||||||
|
root["espFreeHeap"] = ESP.getFreeHeap();
|
||||||
|
root["espHeapSize"] = ESP.getHeapSize();
|
||||||
|
|
||||||
|
root["rssi"] = WiFi.RSSI();
|
||||||
|
|
||||||
|
AsyncResponseStream *response =
|
||||||
|
request->beginResponseStream("application/json");
|
||||||
|
serializeJson(root, *response);
|
||||||
|
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
void onApiSettingsGet(AsyncWebServerRequest *request)
|
void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
JsonDocument root;
|
JsonDocument root;
|
||||||
|
@ -38,16 +71,37 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
root[setting] = preferences.getUInt(setting.c_str());
|
root[setting] = preferences.getUInt(setting.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String setting : intSettings)
|
||||||
|
{
|
||||||
|
root[setting] = preferences.getInt(setting.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
for (String setting : stringSettings)
|
for (String setting : stringSettings)
|
||||||
{
|
{
|
||||||
root[setting] = preferences.getString(setting.c_str());
|
root[setting] = preferences.getString(setting.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String setting : charSettings)
|
||||||
|
{
|
||||||
|
root[setting] = preferences.getChar(setting.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
for (String setting : boolSettings)
|
for (String setting : boolSettings)
|
||||||
{
|
{
|
||||||
root[setting] = preferences.getBool(setting.c_str());
|
root[setting] = preferences.getBool(setting.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root["hostname"] = getMyHostname();
|
||||||
|
root["ip"] = WiFi.localIP();
|
||||||
|
root["txPower"] = WiFi.getTxPower();
|
||||||
|
|
||||||
|
#ifdef GIT_REV
|
||||||
|
root["gitRev"] = String(GIT_REV);
|
||||||
|
#endif
|
||||||
|
#ifdef LAST_BUILD_TIME
|
||||||
|
root["lastBuildTime"] = String(LAST_BUILD_TIME);
|
||||||
|
#endif
|
||||||
|
|
||||||
AsyncResponseStream *response =
|
AsyncResponseStream *response =
|
||||||
request->beginResponseStream("application/json");
|
request->beginResponseStream("application/json");
|
||||||
serializeJson(root, *response);
|
serializeJson(root, *response);
|
||||||
|
@ -69,6 +123,16 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String setting : intSettings)
|
||||||
|
{
|
||||||
|
if (settings.containsKey(setting))
|
||||||
|
{
|
||||||
|
preferences.putInt(setting.c_str(), settings[setting].as<int>());
|
||||||
|
Serial.printf("Setting %s to %d\r\n", setting.c_str(),
|
||||||
|
settings[setting].as<uint>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (String setting : stringSettings)
|
for (String setting : stringSettings)
|
||||||
{
|
{
|
||||||
if (settings.containsKey(setting))
|
if (settings.containsKey(setting))
|
||||||
|
@ -79,6 +143,16 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String setting : charSettings)
|
||||||
|
{
|
||||||
|
if (settings.containsKey(setting))
|
||||||
|
{
|
||||||
|
preferences.putChar(setting.c_str(), settings[setting].as<char>());
|
||||||
|
Serial.printf("Setting %s to %s\r\n", setting.c_str(),
|
||||||
|
settings[setting].as<String>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (String setting : boolSettings)
|
for (String setting : boolSettings)
|
||||||
{
|
{
|
||||||
if (settings.containsKey(setting))
|
if (settings.containsKey(setting))
|
||||||
|
@ -112,3 +186,21 @@ void onNotFound(AsyncWebServerRequest *request)
|
||||||
request->send(404);
|
request->send(404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onApiRestart(AsyncWebServerRequest *request) {
|
||||||
|
request->send(200);
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Api
|
||||||
|
* @Path("/api/full_refresh")
|
||||||
|
*/
|
||||||
|
void onApiFullRefresh(AsyncWebServerRequest *request) {
|
||||||
|
display.refresh();
|
||||||
|
|
||||||
|
request->send(200);
|
||||||
|
}
|
|
@ -9,8 +9,12 @@
|
||||||
|
|
||||||
void setupWebserver();
|
void setupWebserver();
|
||||||
|
|
||||||
|
void onApiStatus(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
void onApiSettingsGet(AsyncWebServerRequest *request);
|
void onApiSettingsGet(AsyncWebServerRequest *request);
|
||||||
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json);
|
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json);
|
||||||
|
void onApiFullRefresh(AsyncWebServerRequest *request);
|
||||||
|
void onApiRestart(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
void onIndex(AsyncWebServerRequest *request);
|
void onIndex(AsyncWebServerRequest *request);
|
||||||
void onNotFound(AsyncWebServerRequest *request);
|
void onNotFound(AsyncWebServerRequest *request);
|
Loading…
Add table
Reference in a new issue