delete unneccessary ui elements

use uint_8 for all index types
fix some minor errors
This commit is contained in:
lukas 2021-03-07 17:45:03 +01:00
parent d44f3bbb06
commit 6d06bf103e
12 changed files with 106 additions and 260 deletions

View File

@ -13,8 +13,8 @@ build_flags =
; Access point settings
-D FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED
-D FACTORY_AP_SSID=\"ESP8266-React-#{unique_id}\" ; 1-64 characters, supports placeholders
-D FACTORY_AP_PASSWORD=\"esp-react\" ; 8-64 characters
-D FACTORY_AP_SSID=\"WordClock-#{unique_id}\" ; 1-64 characters, supports placeholders
-D FACTORY_AP_PASSWORD=\"wordclock\" ; 8-64 characters
-D FACTORY_AP_CHANNEL=1
-D FACTORY_AP_SSID_HIDDEN=false
-D FACTORY_AP_MAX_CLIENTS=4
@ -30,7 +30,7 @@ build_flags =
; NTP settings
-D FACTORY_NTP_ENABLED=true
-D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\"
-D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/Vienna\"
-D FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\"
-D FACTORY_NTP_SERVER=\"time.google.com\"

View File

@ -8,9 +8,7 @@ import { MenuAppBar } from '../components';
import { AuthenticatedRoute } from '../authentication';
import DemoInformation from './DemoInformation';
import LightStateRestController from './LightStateRestController';
import LightStateWebSocketController from './LightStateWebSocketController';
import LightMqttSettingsController from './LightMqttSettingsController';
class DemoProject extends Component<RouteComponentProps> {
@ -20,18 +18,14 @@ class DemoProject extends Component<RouteComponentProps> {
render() {
return (
<MenuAppBar sectionTitle="Demo Project">
<MenuAppBar sectionTitle="WordClock">
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" />
<Tab value={`/${PROJECT_PATH}/demo/rest`} label="REST Controller" />
<Tab value={`/${PROJECT_PATH}/demo/socket`} label="WebSocket Controller" />
<Tab value={`/${PROJECT_PATH}/demo/mqtt`} label="MQTT Controller" />
<Tab value={`/${PROJECT_PATH}/demo/socket`} label="Settings" />
</Tabs>
<Switch>
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/information`} component={DemoInformation} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/rest`} component={LightStateRestController} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/socket`} component={LightStateWebSocketController} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/mqtt`} component={LightMqttSettingsController} />
<Redirect to={`/${PROJECT_PATH}/demo/information`} />
</Switch>
</MenuAppBar>

View File

@ -1,90 +0,0 @@
import React, { Component } from 'react';
import { ValidatorForm, TextValidator } from 'react-material-ui-form-validator';
import { Typography, Box } from '@material-ui/core';
import SaveIcon from '@material-ui/icons/Save';
import { ENDPOINT_ROOT } from '../api';
import { restController, RestControllerProps, RestFormLoader, RestFormProps, FormActions, FormButton, SectionContent } from '../components';
import { LightMqttSettings } from './types';
export const LIGHT_BROKER_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "brokerSettings";
type LightMqttSettingsControllerProps = RestControllerProps<LightMqttSettings>;
class LightMqttSettingsController extends Component<LightMqttSettingsControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title='MQTT Controller' titleGutter>
<RestFormLoader
{...this.props}
render={props => (
<LightMqttSettingsControllerForm {...props} />
)}
/>
</SectionContent>
)
}
}
export default restController(LIGHT_BROKER_SETTINGS_ENDPOINT, LightMqttSettingsController);
type LightMqttSettingsControllerFormProps = RestFormProps<LightMqttSettings>;
function LightMqttSettingsControllerForm(props: LightMqttSettingsControllerFormProps) {
const { data, saveData, handleValueChange } = props;
return (
<ValidatorForm onSubmit={saveData}>
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
<Typography variant="body1">
The LED is controllable via MQTT with the demo project designed to work with Home Assistant's auto discovery feature.
</Typography>
</Box>
<TextValidator
validators={['required']}
errorMessages={['Unique ID is required']}
name="unique_id"
label="Unique ID"
fullWidth
variant="outlined"
value={data.unique_id}
onChange={handleValueChange('unique_id')}
margin="normal"
/>
<TextValidator
validators={['required']}
errorMessages={['Name is required']}
name="name"
label="Name"
fullWidth
variant="outlined"
value={data.name}
onChange={handleValueChange('name')}
margin="normal"
/>
<TextValidator
validators={['required']}
errorMessages={['MQTT Path is required']}
name="mqtt_path"
label="MQTT Path"
fullWidth
variant="outlined"
value={data.mqtt_path}
onChange={handleValueChange('mqtt_path')}
margin="normal"
/>
<FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
Save
</FormButton>
</FormActions>
</ValidatorForm>
);
}

View File

@ -1,67 +0,0 @@
import React, { Component } from 'react';
import { ValidatorForm } from 'react-material-ui-form-validator';
import { Typography, Box, Checkbox } from '@material-ui/core';
import SaveIcon from '@material-ui/icons/Save';
import { ENDPOINT_ROOT } from '../api';
import { restController, RestControllerProps, RestFormLoader, RestFormProps, FormActions, FormButton, SectionContent, BlockFormControlLabel } from '../components';
import { LightState } from './types';
export const LIGHT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "lightState";
type LightStateRestControllerProps = RestControllerProps<LightState>;
class LightStateRestController extends Component<LightStateRestControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title='REST Controller' titleGutter>
<RestFormLoader
{...this.props}
render={props => (
<LightStateRestControllerForm {...props} />
)}
/>
</SectionContent>
)
}
}
export default restController(LIGHT_SETTINGS_ENDPOINT, LightStateRestController);
type LightStateRestControllerFormProps = RestFormProps<LightState>;
function LightStateRestControllerForm(props: LightStateRestControllerFormProps) {
const { data, saveData, handleValueChange } = props;
return (
<ValidatorForm onSubmit={saveData}>
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
<Typography variant="body1">
The form below controls the LED via the RESTful service exposed by the ESP device.
</Typography>
</Box>
<BlockFormControlLabel
control={
<Checkbox
checked={data.led_on}
onChange={handleValueChange('led_on')}
color="primary"
/>
}
label="LED State?"
/>
<FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
Save
</FormButton>
</FormActions>
</ValidatorForm>
);
}

View File

@ -16,7 +16,7 @@ class ProjectMenu extends Component<RouteComponentProps> {
<ListItemIcon>
<SettingsRemoteIcon />
</ListItemIcon>
<ListItemText primary="Demo Project" />
<ListItemText primary="WordClock" />
</ListItem>
</List>
)

View File

@ -1,9 +1,3 @@
export interface LightState {
led_on: boolean;
}
export interface LightMqttSettings {
unique_id : string;
name: string;
mqtt_path : string;
}
}

View File

@ -13,7 +13,19 @@ void Clock::init() {
strip.clear();
strip.show();
refreshTicker.attach(10, [this]() { this->refreshTime(); });
turnOn();
}
void Clock::turnOff() {
strip.clear();
strip.show();
refreshTicker.detach();
}
void Clock::turnOn() {
if (!refreshTicker.active())
refreshTicker.attach(10, [this]() { this->refreshTime(); });
this->refreshTime();
}
@ -22,7 +34,7 @@ void Clock::paintAllwaysOnLeds() {
printWord(types::ist, Adafruit_NeoPixel::Color(150, 0, 150));
}
void Clock::printWord(std::vector<int> word, uint32_t color) {
void Clock::printWord(const std::vector<uint8_t>& word, uint32_t color) {
for (const int i : word) {
strip.setPixelColor(i, color);
}
@ -46,12 +58,7 @@ void Clock::refreshTime() {
paintAllwaysOnLeds();
setTime(hour, minute);
strip.show();
Serial.print("time now: ");
Serial.print(hour);
Serial.print("h ");
Serial.print(minute);
Serial.println("M");
Serial.printf("Time now: %sh %sM", &hour, &minute);
}
void Clock::setTime(uint8_t hour, uint8_t minute) {
@ -65,11 +72,10 @@ void Clock::setTime(uint8_t hour, uint8_t minute) {
if (hour >= 12)
hour = hour - 12;
std::vector<int> hourWord;
hourWord = hour == 1 ? types::ein
std::vector<uint8_t> hourWord;
hourWord = hour == 1 ? (minuteselector == 0 ? types::ein : types::eins) // eins only on a full hour
: hour == 2 ? types::zwei
: hour == 3 ? types::drei
: hour == 3 ? types::drei2
: hour == 4 ? types::vier
: hour == 5 ? types::fuenf2
: hour == 6 ? types::sechs
@ -84,7 +90,7 @@ void Clock::setTime(uint8_t hour, uint8_t minute) {
printWord(hourWord, Adafruit_NeoPixel::Color(0, 150, 0));
// fuenf / zehn / viertl word
std::vector<int> minuteWord;
std::vector<uint8_t> minuteWord;
if (minuteselector == 1 || minuteselector == 5 || minuteselector == 7 || minuteselector == 11)
minuteWord = types::fuenf;
else if (minuteselector == 2 || minuteselector == 4 || minuteselector == 8 || minuteselector == 10)
@ -99,7 +105,7 @@ void Clock::setTime(uint8_t hour, uint8_t minute) {
printWord(minuteWord, Adafruit_NeoPixel::Color(0, 150, 0));
// vor / nach
std::vector<int> vornachWord;
std::vector<uint8_t> vornachWord;
if (minuteselector == 1 || minuteselector == 2 || minuteselector == 3 || minuteselector == 7 || minuteselector == 8)
vornachWord = types::nach;
else if (minuteselector == 4 || minuteselector == 5 || minuteselector == 10 || minuteselector == 11)

View File

@ -18,13 +18,16 @@ class Clock {
LoadAnimator animator;
void paintAllwaysOnLeds();
void printWord(std::vector<int> word, uint32_t color);
void printWord(const std::vector<uint8_t>& word, uint32_t color);
void setTime(uint8_t hour, uint8_t minute);
void refreshTime();
public:
Clock();
void init();
void refreshTime();
void turnOff();
void turnOn();
Ticker refreshTicker;
};

View File

@ -5,34 +5,36 @@
#include "ClockService.h"
ClockService::ClockService(AsyncWebServer* server, SecurityManager* securityManager) :
_httpEndpoint(LightState::read,
LightState::update,
_httpEndpoint(WordClockState::read,
WordClockState::update,
this,
server,
LIGHT_SETTINGS_ENDPOINT_PATH,
securityManager,
AuthenticationPredicates::IS_AUTHENTICATED),
_webSocket(LightState::read,
LightState::update,
_webSocket(WordClockState::read,
WordClockState::update,
this,
server,
LIGHT_SETTINGS_SOCKET_PATH,
securityManager,
AuthenticationPredicates::IS_AUTHENTICATED),
clock() {
// configure led to be output
pinMode(LED_PIN, OUTPUT);
// configure settings service update handler to update LED state
addUpdateHandler([&](const String& originId) { onConfigUpdated(); }, false);
}
void ClockService::begin() {
_state.ledOn = DEFAULT_LED_STATE;
_state.wordClockOn = DEFAULT_CLOCK_STATE;
onConfigUpdated();
clock.init();
}
void ClockService::onConfigUpdated() {
digitalWrite(LED_PIN, _state.ledOn ? LED_ON : LED_OFF);
// digitalWrite(LED_PIN, _state.ledOn ? LED_ON : LED_OFF);
if (_state.wordClockOn) {
clock.turnOn();
} else {
clock.turnOff();
}
}

View File

@ -9,48 +9,39 @@
#include <WebSocketTxRx.h>
#include "Clock.h"
#define LED_PIN 2
#define PRINT_DELAY 5000
#define DEFAULT_LED_STATE false
#define DEFAULT_CLOCK_STATE true
#define OFF_STATE "OFF"
#define ON_STATE "ON"
// Note that the built-in LED is on when the pin is low on most NodeMCU boards.
// This is because the anode is tied to VCC and the cathode to the GPIO 4 (Arduino pin 2).
#ifdef ESP32
#define LED_ON 0x1
#define LED_OFF 0x0
#elif defined(ESP8266)
#define LED_ON 0x0
#define LED_OFF 0x1
#endif
#define CLOCK_ON 0x1
#define CLOCK_OFF 0x0
#define LIGHT_SETTINGS_ENDPOINT_PATH "/rest/lightState"
#define LIGHT_SETTINGS_SOCKET_PATH "/ws/lightState"
class LightState {
class WordClockState {
public:
bool ledOn;
bool wordClockOn;
static void read(LightState& settings, JsonObject& root) {
root["led_on"] = settings.ledOn;
static void read(WordClockState& settings, JsonObject& root) {
root["led_on"] = settings.wordClockOn;
}
static StateUpdateResult update(JsonObject& root, LightState& lightState) {
boolean newState = root["led_on"] | DEFAULT_LED_STATE;
if (lightState.ledOn != newState) {
lightState.ledOn = newState;
static StateUpdateResult update(JsonObject& root, WordClockState& lightState) {
boolean newState = root["led_on"] | DEFAULT_CLOCK_STATE;
if (lightState.wordClockOn != newState) {
lightState.wordClockOn = newState;
return StateUpdateResult::CHANGED;
}
return StateUpdateResult::UNCHANGED;
}
static void haRead(LightState& settings, JsonObject& root) {
root["state"] = settings.ledOn ? ON_STATE : OFF_STATE;
static void haRead(WordClockState& settings, JsonObject& root) {
root["state"] = settings.wordClockOn ? ON_STATE : OFF_STATE;
}
static StateUpdateResult haUpdate(JsonObject& root, LightState& lightState) {
static StateUpdateResult haUpdate(JsonObject& root, WordClockState& lightState) {
String state = root["state"];
// parse new led state
boolean newState = false;
@ -60,22 +51,22 @@ class LightState {
return StateUpdateResult::ERROR;
}
// change the new state, if required
if (lightState.ledOn != newState) {
lightState.ledOn = newState;
if (lightState.wordClockOn != newState) {
lightState.wordClockOn = newState;
return StateUpdateResult::CHANGED;
}
return StateUpdateResult::UNCHANGED;
}
};
class ClockService : public StatefulService<LightState> {
class ClockService : public StatefulService<WordClockState> {
public:
ClockService(AsyncWebServer* server, SecurityManager* securityManager);
void begin();
private:
HttpEndpoint<LightState> _httpEndpoint;
WebSocketTxRx<LightState> _webSocket;
HttpEndpoint<WordClockState> _httpEndpoint;
WebSocketTxRx<WordClockState> _webSocket;
Clock clock;

View File

@ -4,32 +4,32 @@
#include "Types.h"
const std::vector<int> types::es = calcPixels(0, 0, 2);
const std::vector<int> types::ist = calcPixels(3, 0, 3);
const std::vector<int> types::fuenf = calcPixels(8, 0, 4);
const std::vector<int> types::zehn = calcPixels(0, 1, 4);
const std::vector<int> types::zwanzig = calcPixels(5, 1, 7);
const std::vector<int> types::drei = calcPixels(1, 2, 3);
const std::vector<int> types::viertel = calcPixels(5, 2, 7);
const std::vector<int> types::dreiviertel = calcPixels(1, 2, 11);
const std::vector<int> types::vor = calcPixels(0, 3, 3);
const std::vector<int> types::nach = calcPixels(3, 3, 4);
const std::vector<int> types::halb = calcPixels(8, 3, 4);
const std::vector<int> types::zwoelf = calcPixels(0, 4, 5);
const std::vector<int> types::sieben = calcPixels(6, 4, 6);
const std::vector<int> types::ein = calcPixels(0, 5, 3);
const std::vector<int> types::eins = calcPixels(0, 5, 4);
const std::vector<int> types::vier = calcPixels(4, 5, 4);
const std::vector<int> types::acht = calcPixels(8, 5, 4);
const std::vector<int> types::sechs = calcPixels(0, 6, 5);
const std::vector<int> types::zwei = calcPixels(6, 6, 5);
const std::vector<int> types::fuenf2 = calcPixels(1, 7, 5);
const std::vector<int> types::elf = calcPixels(5, 7, 3);
const std::vector<int> types::zehn2 = calcPixels(8, 7, 4);
const std::vector<int> types::neun = calcPixels(0, 8, 4);
const std::vector<int> types::drei2 = calcPixels(4, 8, 4);
const std::vector<int> types::ein2 = calcPixels(6, 8, 3);
const std::vector<int> types::uhr = calcPixels(9, 8, 3);
const std::vector<uint8_t> types::es = calcPixels(0, 0, 2);
const std::vector<uint8_t> types::ist = calcPixels(3, 0, 3);
const std::vector<uint8_t> types::fuenf = calcPixels(8, 0, 4);
const std::vector<uint8_t> types::zehn = calcPixels(0, 1, 4);
const std::vector<uint8_t> types::zwanzig = calcPixels(5, 1, 7);
const std::vector<uint8_t> types::drei = calcPixels(1, 2, 4);
const std::vector<uint8_t> types::viertel = calcPixels(5, 2, 7);
const std::vector<uint8_t> types::dreiviertel = calcPixels(1, 2, 11);
const std::vector<uint8_t> types::vor = calcPixels(0, 3, 3);
const std::vector<uint8_t> types::nach = calcPixels(3, 3, 4);
const std::vector<uint8_t> types::halb = calcPixels(8, 3, 4);
const std::vector<uint8_t> types::zwoelf = calcPixels(0, 4, 5);
const std::vector<uint8_t> types::sieben = calcPixels(6, 4, 6);
const std::vector<uint8_t> types::ein = calcPixels(0, 5, 3);
const std::vector<uint8_t> types::eins = calcPixels(0, 5, 4);
const std::vector<uint8_t> types::vier = calcPixels(4, 5, 4);
const std::vector<uint8_t> types::acht = calcPixels(8, 5, 4);
const std::vector<uint8_t> types::sechs = calcPixels(0, 6, 5);
const std::vector<uint8_t> types::zwei = calcPixels(6, 6, 4);
const std::vector<uint8_t> types::fuenf2 = calcPixels(1, 7, 4);
const std::vector<uint8_t> types::elf = calcPixels(5, 7, 3);
const std::vector<uint8_t> types::zehn2 = calcPixels(8, 7, 4);
const std::vector<uint8_t> types::neun = calcPixels(0, 8, 4);
const std::vector<uint8_t> types::drei2 = calcPixels(4, 8, 4);
const std::vector<uint8_t> types::ein2 = calcPixels(6, 8, 3);
const std::vector<uint8_t> types::uhr = calcPixels(9, 8, 3);
uint8_t types::convert(uint8_t x, uint8_t y) {
const bool upRow = (x % 2) == 0;
@ -42,8 +42,8 @@ uint8_t types::convert(uint8_t x, uint8_t y) {
return val;
}
std::vector<int> types::calcPixels(uint8_t x, uint8_t y, uint8_t nrPixels) {
std::vector<int> vec;
std::vector<uint8_t> types::calcPixels(uint8_t x, uint8_t y, uint8_t nrPixels) {
std::vector<uint8_t> vec;
for (uint8_t i = 0; i < nrPixels; i++) {
vec.push_back(convert(x + i, y));
}

View File

@ -8,7 +8,7 @@
#include "Arduino.h"
struct types {
static const std::vector<int>
static const std::vector<uint8_t>
es, ist, fuenf,
zehn, zwanzig, drei,
viertel, dreiviertel, vor,
@ -19,9 +19,22 @@ struct types {
zehn2, neun, drei2,
ein2, uhr;
/**
* convert an x/y coordinate into the corresponding strip index value
* @param x x axis value
* @param y y axis value
* @return strip led index (zero beginning)
*/
static uint8_t convert(uint8_t x, uint8_t y);
static std::vector<int> calcPixels(uint8_t x, uint8_t y, uint8_t nrPixels);
/**
* calculate all pixels within a pixelrange for a word
* @param x x axis value
* @param y y axis value
* @param nrPixels number of pixels the word contains
* @return array of strip indexes
*/
static std::vector<uint8_t> calcPixels(uint8_t x, uint8_t y, uint8_t nrPixels);
};
#endif // LEDSTRIPINTERFACE_TYPES_H