Merge branch 'twentyaftersyntyx' into 'master'
add option to switch to the TwentyAfter Syntax and show UHR always See merge request lukas/ledstripinterface!1
This commit is contained in:
commit
4ed74164e8
2
interface/package-lock.json
generated
2
interface/package-lock.json
generated
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "esp8266-react",
|
"name": "wordclock",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
|
@ -1,77 +1,91 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Typography, Box, List, ListItem, ListItemText } from '@material-ui/core';
|
import {Typography, Switch} from '@material-ui/core';
|
||||||
import { SectionContent } from '../components';
|
import {
|
||||||
|
BlockFormControlLabel,
|
||||||
|
SectionContent,
|
||||||
|
webSocketController,
|
||||||
|
WebSocketControllerProps,
|
||||||
|
WebSocketFormLoader,
|
||||||
|
WebSocketFormProps
|
||||||
|
} from '../components';
|
||||||
|
|
||||||
class DemoInformation extends Component {
|
import {InformationState} from "./types";
|
||||||
|
import {WEB_SOCKET_ROOT} from "../api";
|
||||||
|
import {ValidatorForm} from "react-material-ui-form-validator";
|
||||||
|
|
||||||
|
export const INFORMATION_WEBSOCKET_URL = WEB_SOCKET_ROOT + "information";
|
||||||
|
type InformationStateWebSocketControllerProps = WebSocketControllerProps<InformationState>;
|
||||||
|
|
||||||
|
class DemoInformation extends Component<InformationStateWebSocketControllerProps> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SectionContent title='Demo Information' titleGutter>
|
<SectionContent title='WordClock Information' titleGutter>
|
||||||
<Typography variant="body1" paragraph>
|
<Typography variant="body1" paragraph>
|
||||||
This simple demo project allows you to control the built-in LED.
|
Welcome to the WordClock Overview page. Here you can turn on and off your WordClock and set Basic Settings
|
||||||
It demonstrates how the esp8266-react framework may be extended for your own IoT project.
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" paragraph>
|
<WebSocketFormLoader
|
||||||
It is recommended that you keep your project interface code under the project directory.
|
{...this.props}
|
||||||
This serves to isolate your project code from the from the rest of the user interface which should
|
render={props => (
|
||||||
simplify merges should you wish to update your project with future framework changes.
|
<LightStateWebSocketControllerForm {...props} />
|
||||||
</Typography>
|
)}
|
||||||
<Typography variant="body1" paragraph>
|
|
||||||
The demo project interface code is stored in the 'interface/src/project' directory:
|
|
||||||
</Typography>
|
|
||||||
<List>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="ProjectMenu.tsx"
|
|
||||||
secondary="You can add your project's screens to the side bar here."
|
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="ProjectRouting.tsx"
|
|
||||||
secondary="The routing which controls the screens of your project."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="DemoProject.tsx"
|
|
||||||
secondary="This screen, with tabs and tab routing."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="DemoInformation.tsx"
|
|
||||||
secondary="The demo information page."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="LightStateRestController.tsx"
|
|
||||||
secondary="A form which lets the user control the LED over a REST service."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="LightStateWebSocketController.tsx"
|
|
||||||
secondary="A form which lets the user control and monitor the status of the LED over WebSockets."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem>
|
|
||||||
<ListItemText
|
|
||||||
primary="LightMqttSettingsController.tsx"
|
|
||||||
secondary="A form which lets the user change the MQTT settings for MQTT based control of the LED."
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
<Box mt={2}>
|
|
||||||
<Typography variant="body1">
|
|
||||||
See the project <a href="https://github.com/rjwats/esp8266-react/">README</a> for a full description of the demo project.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DemoInformation;
|
export default webSocketController(INFORMATION_WEBSOCKET_URL, 100, DemoInformation);
|
||||||
|
|
||||||
|
type InformationWebSocketControllerFormProps = WebSocketFormProps<InformationState>;
|
||||||
|
|
||||||
|
function LightStateWebSocketControllerForm(props: InformationWebSocketControllerFormProps) {
|
||||||
|
const { data, saveData, setData } = props;
|
||||||
|
|
||||||
|
const changeWordClockOn = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setData({wordclockOn: event.target.checked,twentyAfterSyntax: data.twentyAfterSyntax, uhrAlwaysOn: data.uhrAlwaysOn }, saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeTwentyAfterSyntax = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setData({wordclockOn: data.wordclockOn, twentyAfterSyntax: event.target.checked, uhrAlwaysOn: data.uhrAlwaysOn }, saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeUhrAlwaysOn = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setData({wordclockOn: data.wordclockOn,twentyAfterSyntax: data.twentyAfterSyntax, uhrAlwaysOn: event.target.checked }, saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ValidatorForm onSubmit={saveData}>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={data.wordclockOn}
|
||||||
|
onChange={changeWordClockOn}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="WordClock turned on?"
|
||||||
|
/>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={data.twentyAfterSyntax}
|
||||||
|
onChange={changeTwentyAfterSyntax}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Use Twenty-After Syntax?"
|
||||||
|
/>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={data.uhrAlwaysOn}
|
||||||
|
onChange={changeUhrAlwaysOn}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Always Display UHR label"
|
||||||
|
/>
|
||||||
|
</ValidatorForm>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
export interface LightState {
|
export interface LightState {
|
||||||
led_on: boolean;
|
led_on: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InformationState {
|
||||||
|
wordclockOn: boolean;
|
||||||
|
twentyAfterSyntax: boolean;
|
||||||
|
uhrAlwaysOn: boolean;
|
||||||
|
}
|
@ -2,10 +2,10 @@
|
|||||||
// Created by lukas on 06.03.21.
|
// Created by lukas on 06.03.21.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Clock.h"
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "Clock.h"
|
||||||
|
|
||||||
Clock::Clock() : strip(NUMPIXELS, D5, NEO_GRB + NEO_KHZ800), animator(), refreshTicker() {
|
Clock::Clock() : strip(NUMPIXELS, STRIPPIN, NEO_GRB + NEO_KHZ800), animator(), refreshTicker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clock::init() {
|
void Clock::init() {
|
||||||
@ -28,13 +28,13 @@ void Clock::turnOn() {
|
|||||||
this->refreshTime();
|
this->refreshTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clock::paintAllwaysOnLeds() {
|
void Clock::paintAlwaysOnLeds() {
|
||||||
printWord(types::es, Adafruit_NeoPixel::Color(150, 150, 0));
|
printWord(types::es, Adafruit_NeoPixel::Color(150, 150, 0));
|
||||||
printWord(types::ist, Adafruit_NeoPixel::Color(150, 0, 150));
|
printWord(types::ist, Adafruit_NeoPixel::Color(150, 0, 150));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clock::printWord(const std::vector<uint8_t>& word, uint32_t color) {
|
void Clock::printWord(const std::vector<uint8_t>& word, uint32_t color) {
|
||||||
for (const int i : word) {
|
for (const uint8_t i : word) {
|
||||||
strip.setPixelColor(i, color);
|
strip.setPixelColor(i, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,17 +54,18 @@ void Clock::refreshTime() {
|
|||||||
const uint8_t hour = loctime->tm_hour;
|
const uint8_t hour = loctime->tm_hour;
|
||||||
const uint8_t minute = loctime->tm_min;
|
const uint8_t minute = loctime->tm_min;
|
||||||
|
|
||||||
paintAllwaysOnLeds();
|
paintAlwaysOnLeds();
|
||||||
setTime(hour, minute);
|
setTime(hour, minute, this->twentyAfterSyntax, this->clockAlwaysOn);
|
||||||
|
|
||||||
strip.show();
|
strip.show();
|
||||||
Serial.printf("Time now: %sh %sM", &hour, &minute);
|
Serial.printf("Time now: %uh %uM\n", hour, minute);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clock::setTime(uint8_t hour, uint8_t minute) {
|
void Clock::setTime(uint8_t hour, uint8_t minute, bool twentyAfterSyntax, bool alwaysClockWord) {
|
||||||
const uint8_t minuteselector = minute / 5;
|
const uint8_t minuteselector = minute / 5;
|
||||||
|
|
||||||
// if minuteselector >= 4 +1 to hour
|
// if minuteselector >= 4 +1 to hour
|
||||||
if (minuteselector >= 4)
|
if (twentyAfterSyntax ? minuteselector >= 5 : minuteselector >= 4)
|
||||||
hour++;
|
hour++;
|
||||||
|
|
||||||
// convert to 12h format
|
// convert to 12h format
|
||||||
@ -86,36 +87,69 @@ void Clock::setTime(uint8_t hour, uint8_t minute) {
|
|||||||
: hour == 0 || hour == 12 ? types::zwoelf
|
: hour == 0 || hour == 12 ? types::zwoelf
|
||||||
: hourWord;
|
: hourWord;
|
||||||
|
|
||||||
printWord(hourWord, Adafruit_NeoPixel::Color(0, 150, 0));
|
printWord(hourWord, Adafruit_NeoPixel::Color(0, 0, 150));
|
||||||
|
|
||||||
|
// print the minute words and the corresponding after/before half words
|
||||||
|
printMinutes(minuteselector, twentyAfterSyntax);
|
||||||
|
|
||||||
|
// uhr
|
||||||
|
if (minuteselector == 0 || alwaysClockWord)
|
||||||
|
printWord(types::uhr, Adafruit_NeoPixel::Color(150, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::printMinutes(uint8_t minuteSelector, bool twentyAfterSyntax) {
|
||||||
// fuenf / zehn / viertl word
|
// fuenf / zehn / viertl word
|
||||||
std::vector<uint8_t> minuteWord;
|
std::vector<uint8_t> minuteWord;
|
||||||
if (minuteselector == 1 || minuteselector == 5 || minuteselector == 7 || minuteselector == 11)
|
if (minuteSelector == 1 || minuteSelector == 5 || minuteSelector == 7 || minuteSelector == 11) {
|
||||||
minuteWord = types::fuenf;
|
minuteWord = types::fuenf;
|
||||||
else if (minuteselector == 2 || minuteselector == 4 || minuteselector == 8 || minuteselector == 10)
|
} else if (minuteSelector == 2 || minuteSelector == 4 || minuteSelector == 8 || minuteSelector == 10) {
|
||||||
|
// check if we use the twenty after syntax
|
||||||
|
if ((minuteSelector == 4 || minuteSelector == 8) && twentyAfterSyntax)
|
||||||
|
minuteWord = types::zwanzig;
|
||||||
|
else
|
||||||
minuteWord = types::zehn;
|
minuteWord = types::zehn;
|
||||||
else if (minuteselector == 3)
|
} else if (minuteSelector == 3)
|
||||||
minuteWord = types::viertel;
|
minuteWord = types::viertel;
|
||||||
else if (minuteselector == 9)
|
else if (minuteSelector == 9)
|
||||||
minuteWord = types::dreiviertel;
|
minuteWord = types::dreiviertel;
|
||||||
else if (minuteselector == 6)
|
else if (minuteSelector == 6)
|
||||||
minuteWord = types::halb;
|
minuteWord = types::halb;
|
||||||
|
|
||||||
printWord(minuteWord, Adafruit_NeoPixel::Color(0, 150, 0));
|
printWord(minuteWord, Adafruit_NeoPixel::Color(0, 150, 0));
|
||||||
|
|
||||||
// vor / nach
|
// vor / nach
|
||||||
std::vector<uint8_t> vornachWord;
|
std::vector<uint8_t> vornachWord;
|
||||||
if (minuteselector == 1 || minuteselector == 2 || minuteselector == 3 || minuteselector == 7 || minuteselector == 8)
|
if (minuteSelector == 1 || minuteSelector == 2 || minuteSelector == 3 ||
|
||||||
|
((minuteSelector == 8) &&
|
||||||
|
!twentyAfterSyntax) || // check if twentyafter syntax is enabled - if not display the the after
|
||||||
|
minuteSelector == 7 ||
|
||||||
|
((minuteSelector == 4) &&
|
||||||
|
twentyAfterSyntax)) // check if twentyafter syntax is enabled - if yes display the the after
|
||||||
vornachWord = types::nach;
|
vornachWord = types::nach;
|
||||||
else if (minuteselector == 4 || minuteselector == 5 || minuteselector == 10 || minuteselector == 11)
|
else if (minuteSelector == 5 ||
|
||||||
|
((minuteSelector == 4) && !twentyAfterSyntax) // check if twentyafter enabled if not -- display vor
|
||||||
|
|| minuteSelector == 10 || minuteSelector == 11 ||
|
||||||
|
((minuteSelector == 8) && twentyAfterSyntax)) // check if twentyafter enabled if yess -- display vor
|
||||||
vornachWord = types::vor;
|
vornachWord = types::vor;
|
||||||
printWord(vornachWord, Adafruit_NeoPixel::Color(150, 150, 150));
|
printWord(vornachWord, Adafruit_NeoPixel::Color(150, 150, 150));
|
||||||
|
|
||||||
// halb
|
// halb
|
||||||
if (minuteselector >= 4 && minuteselector <= 8)
|
if (minuteSelector >= 4 && minuteSelector <= 8) {
|
||||||
|
// only 3 times if twentyafter syntax is on
|
||||||
|
if (!twentyAfterSyntax || (minuteSelector >= 5 && minuteSelector <= 7))
|
||||||
printWord(types::halb, Adafruit_NeoPixel::Color(150, 0, 0));
|
printWord(types::halb, Adafruit_NeoPixel::Color(150, 0, 0));
|
||||||
|
}
|
||||||
// uhr
|
}
|
||||||
if (minuteselector == 0)
|
|
||||||
printWord(types::uhr, Adafruit_NeoPixel::Color(0, 0, 150));
|
void Clock::useTwentyAfterSyntax(bool twentyAFterSyntax) {
|
||||||
|
this->twentyAfterSyntax = twentyAFterSyntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::useAlwaysOnUhrSyntax(bool alwaysOnUhr) {
|
||||||
|
this->clockAlwaysOn = alwaysOnUhr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock::update() {
|
||||||
|
if (refreshTicker.active())
|
||||||
|
this->refreshTime();
|
||||||
}
|
}
|
48
src/Clock.h
48
src/Clock.h
@ -5,22 +5,57 @@
|
|||||||
#ifndef LEDSTRIPINTERFACE_CLOCK_H
|
#ifndef LEDSTRIPINTERFACE_CLOCK_H
|
||||||
#define LEDSTRIPINTERFACE_CLOCK_H
|
#define LEDSTRIPINTERFACE_CLOCK_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
#include <Ticker.h>
|
#include <Ticker.h>
|
||||||
#include "Adafruit_NeoPixel.h"
|
#include "Adafruit_NeoPixel.h"
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "LoadAnimator.h"
|
#include "LoadAnimator.h"
|
||||||
|
|
||||||
#define NUMPIXELS 108 // Popular NeoPixel ring size
|
// define the strip length of the wordclock
|
||||||
|
#define NUMPIXELS 108
|
||||||
|
// define the esp pin the stip is attached to
|
||||||
|
#define STRIPPIN D5
|
||||||
|
|
||||||
class Clock {
|
class Clock {
|
||||||
private:
|
private:
|
||||||
Adafruit_NeoPixel strip{};
|
Adafruit_NeoPixel strip{};
|
||||||
LoadAnimator animator;
|
LoadAnimator animator;
|
||||||
|
Ticker refreshTicker;
|
||||||
|
|
||||||
void paintAllwaysOnLeds();
|
bool twentyAfterSyntax;
|
||||||
|
bool clockAlwaysOn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* display the words which are always on (Es ist...)
|
||||||
|
*/
|
||||||
|
void paintAlwaysOnLeds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* paint a specific word
|
||||||
|
* @param word word pointer to print
|
||||||
|
* @param color the color in which to print it
|
||||||
|
*/
|
||||||
void printWord(const std::vector<uint8_t>& word, uint32_t color);
|
void printWord(const std::vector<uint8_t>& word, uint32_t color);
|
||||||
void setTime(uint8_t hour, uint8_t minute);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logic to print the correct minute word and its corresponding wods
|
||||||
|
* @param minuteSelector a number between 0 - 11 representing the minute in 5min distances
|
||||||
|
* @param twentyAfterSyntax whether to use a twenty after syntax or a 10min before half syntax
|
||||||
|
*/
|
||||||
|
void printMinutes(uint8_t minuteSelector, bool twentyAfterSyntax);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the whole time of the clock
|
||||||
|
* @param hour hour to set (0-24)
|
||||||
|
* @param minute minute to set(0-59)
|
||||||
|
* @param twentyAfterSyntax whether to use a twenty after syntax or a 10min before half syntax
|
||||||
|
* @param alwaysClockWord print the UHR word always and not only on full hours
|
||||||
|
*/
|
||||||
|
void setTime(uint8_t hour, uint8_t minute, bool twentyAfterSyntax = false, bool alwaysClockWord = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load the current time and set it onto the clock
|
||||||
|
*/
|
||||||
void refreshTime();
|
void refreshTime();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -32,7 +67,7 @@ class Clock {
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* turn of the wordclock
|
* turn off the wordclock
|
||||||
*/
|
*/
|
||||||
void turnOff();
|
void turnOff();
|
||||||
|
|
||||||
@ -41,7 +76,10 @@ class Clock {
|
|||||||
*/
|
*/
|
||||||
void turnOn();
|
void turnOn();
|
||||||
|
|
||||||
Ticker refreshTicker;
|
void useTwentyAfterSyntax(bool twentyAFterSyntax);
|
||||||
|
void useAlwaysOnUhrSyntax(bool alwaysOnUhr);
|
||||||
|
|
||||||
|
void update();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <HttpEndpoint.h>
|
#include <HttpEndpoint.h>
|
||||||
#include <MqttPubSub.h>
|
|
||||||
#include <WebSocketTxRx.h>
|
#include <WebSocketTxRx.h>
|
||||||
#include "Clock.h"
|
#include "Clock.h"
|
||||||
|
|
||||||
|
41
src/InformationService.cpp
Normal file
41
src/InformationService.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 09.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InformationService.h"
|
||||||
|
|
||||||
|
InformationService::InformationService(AsyncWebServer* server, SecurityManager* securityManager) :
|
||||||
|
_webSocket(InformationState::read,
|
||||||
|
InformationState::update,
|
||||||
|
this,
|
||||||
|
server,
|
||||||
|
INFORMATION_SETTINGS_SOCKET_PATH,
|
||||||
|
securityManager,
|
||||||
|
AuthenticationPredicates::IS_AUTHENTICATED),
|
||||||
|
clock() {
|
||||||
|
// configure settings service update handler to update LED state
|
||||||
|
addUpdateHandler([&](const String& originId) { onConfigUpdated(); }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InformationService::begin() {
|
||||||
|
_state.wordClockOn = DEFAULT_CLOCK_STATE;
|
||||||
|
_state.twentyAfterSyntax = true;
|
||||||
|
_state.uhrAlwaysOn = false;
|
||||||
|
|
||||||
|
onConfigUpdated();
|
||||||
|
clock.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InformationService::onConfigUpdated() {
|
||||||
|
// digitalWrite(LED_PIN, _state.ledOn ? LED_ON : LED_OFF);
|
||||||
|
if (_state.wordClockOn) {
|
||||||
|
clock.turnOn();
|
||||||
|
} else {
|
||||||
|
clock.turnOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
clock.useAlwaysOnUhrSyntax(_state.uhrAlwaysOn);
|
||||||
|
clock.useTwentyAfterSyntax(_state.twentyAfterSyntax);
|
||||||
|
|
||||||
|
clock.update();
|
||||||
|
}
|
79
src/InformationService.h
Normal file
79
src/InformationService.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 09.03.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LEDSTRIPINTERFACE_INFORMATIONSERVICE_H
|
||||||
|
#define LEDSTRIPINTERFACE_INFORMATIONSERVICE_H
|
||||||
|
|
||||||
|
#include <HttpEndpoint.h>
|
||||||
|
#include <WebSocketTxRx.h>
|
||||||
|
#include "Clock.h"
|
||||||
|
|
||||||
|
#define DEFAULT_CLOCK_STATE true
|
||||||
|
#define OFF_STATE "OFF"
|
||||||
|
#define ON_STATE "ON"
|
||||||
|
|
||||||
|
#define INFORMATION_SETTINGS_SOCKET_PATH "/ws/information"
|
||||||
|
|
||||||
|
class InformationState {
|
||||||
|
public:
|
||||||
|
bool wordClockOn;
|
||||||
|
bool twentyAfterSyntax;
|
||||||
|
bool uhrAlwaysOn;
|
||||||
|
|
||||||
|
static void read(InformationState& settings, JsonObject& root) {
|
||||||
|
root["wordclockOn"] = settings.wordClockOn;
|
||||||
|
root["twentyAfterSyntax"] = settings.twentyAfterSyntax;
|
||||||
|
root["uhrAlwaysOn"] = settings.uhrAlwaysOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StateUpdateResult update(JsonObject& root, InformationState& lightState) {
|
||||||
|
const bool newOnState = root["wordclockOn"] | DEFAULT_CLOCK_STATE;
|
||||||
|
const bool newTwentyAfterState = root["twentyAfterSyntax"] | DEFAULT_CLOCK_STATE;
|
||||||
|
const bool newUhrAlwaysOnState = root["uhrAlwaysOn"] | DEFAULT_CLOCK_STATE;
|
||||||
|
|
||||||
|
if (lightState.wordClockOn != newOnState || lightState.twentyAfterSyntax != newTwentyAfterState || lightState.uhrAlwaysOn != newUhrAlwaysOnState) {
|
||||||
|
lightState.wordClockOn = newOnState;
|
||||||
|
lightState.twentyAfterSyntax = newTwentyAfterState;
|
||||||
|
lightState.uhrAlwaysOn = newUhrAlwaysOnState;
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
return StateUpdateResult::UNCHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void haRead(InformationState& settings, JsonObject& root) {
|
||||||
|
// root["state"] = settings.wordClockOn ? ON_STATE : OFF_STATE;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// static StateUpdateResult haUpdate(JsonObject& root, InformationState& lightState) {
|
||||||
|
// String state = root["state"];
|
||||||
|
// // parse new led state
|
||||||
|
// boolean newState = false;
|
||||||
|
// if (state.equals(ON_STATE)) {
|
||||||
|
// newState = true;
|
||||||
|
// } else if (!state.equals(OFF_STATE)) {
|
||||||
|
// return StateUpdateResult::ERROR;
|
||||||
|
// }
|
||||||
|
// // change the new state, if required
|
||||||
|
// if (lightState.wordClockOn != newState) {
|
||||||
|
// lightState.wordClockOn = newState;
|
||||||
|
// return StateUpdateResult::CHANGED;
|
||||||
|
// }
|
||||||
|
// return StateUpdateResult::UNCHANGED;
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
class InformationService : public StatefulService<InformationState>{
|
||||||
|
public:
|
||||||
|
InformationService(AsyncWebServer* server, SecurityManager* securityManager);
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
private:
|
||||||
|
WebSocketTxRx<InformationState> _webSocket;
|
||||||
|
|
||||||
|
Clock clock;
|
||||||
|
|
||||||
|
void onConfigUpdated();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LEDSTRIPINTERFACE_INFORMATIONSERVICE_H
|
@ -34,7 +34,7 @@ const std::vector<uint8_t> types::uhr = calcPixels(9, 8, 3);
|
|||||||
uint8_t types::convert(uint8_t x, uint8_t y) {
|
uint8_t types::convert(uint8_t x, uint8_t y) {
|
||||||
const bool upRow = (x % 2) == 0;
|
const bool upRow = (x % 2) == 0;
|
||||||
|
|
||||||
int val = x * 9 + y;
|
uint8_t val = x * 9 + y;
|
||||||
// if its a row upwards we need to calculate the additional down and up pixels
|
// if its a row upwards we need to calculate the additional down and up pixels
|
||||||
if (upRow)
|
if (upRow)
|
||||||
// we need to go the rest down (9 -y) and up (*2) and subtract the too many added 10
|
// we need to go the rest down (9 -y) and up (*2) and subtract the too many added 10
|
||||||
|
10
src/main.cpp
10
src/main.cpp
@ -1,5 +1,6 @@
|
|||||||
#include <ESP8266React.h>
|
#include <ESP8266React.h>
|
||||||
#include "ClockService.h"
|
#include "ClockService.h"
|
||||||
|
#include "InformationService.h"
|
||||||
|
|
||||||
#define SERIAL_BAUD_RATE 115200
|
#define SERIAL_BAUD_RATE 115200
|
||||||
|
|
||||||
@ -9,18 +10,21 @@
|
|||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
ESP8266React esp8266React(&server);
|
ESP8266React esp8266React(&server);
|
||||||
|
|
||||||
ClockService cservice = ClockService(&server, esp8266React.getSecurityManager());
|
//ClockService cservice = ClockService(&server, esp8266React.getSecurityManager());
|
||||||
|
InformationService iservice = InformationService(&server, esp8266React.getSecurityManager());
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// start serial and filesystem
|
// start serial and filesystem
|
||||||
Serial.begin(SERIAL_BAUD_RATE);
|
Serial.begin(SERIAL_BAUD_RATE);
|
||||||
Serial.printf("Starting WordClock %s", VERSION);
|
Serial.printf("Starting WordClock %s\n", VERSION);
|
||||||
|
|
||||||
// start the framework and demo project
|
// start the framework and demo project
|
||||||
esp8266React.begin();
|
esp8266React.begin();
|
||||||
|
|
||||||
// load the initial light settings
|
// load the initial light settings
|
||||||
cservice.begin();
|
// cservice.begin();
|
||||||
|
|
||||||
|
iservice.begin();
|
||||||
|
|
||||||
// start the server
|
// start the server
|
||||||
server.begin();
|
server.begin();
|
||||||
|
Loading…
Reference in New Issue
Block a user