377 lines
12 KiB
YAML
377 lines
12 KiB
YAML
substitutions:
|
|
name_of_board: lasercutter
|
|
ip_addr: "172.23.23.26"
|
|
machines_token: !secret mlock_machines_token
|
|
wifi_ssid: !secret wifi_ssid
|
|
wifi_password: !secret wifi_password
|
|
ota_password: !secret ota_password
|
|
api_enckey: !secret api_enckey
|
|
|
|
###### nothing to change below this line ######
|
|
esphome:
|
|
name: mlock-${name_of_board}
|
|
includes:
|
|
- mlock-common.h
|
|
on_boot:
|
|
- priority: 300
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 100% }
|
|
- priority: -100
|
|
then:
|
|
- if:
|
|
condition:
|
|
switch.is_on: mlock_${name_of_board}_switch
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% }
|
|
else:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
|
|
esp8266:
|
|
board: d1_mini
|
|
restore_from_flash: true # max 96 bytes
|
|
|
|
# Enable logging
|
|
logger:
|
|
level: DEBUG
|
|
|
|
api:
|
|
encryption:
|
|
key: $api_enckey
|
|
|
|
ota:
|
|
password: $ota_password
|
|
|
|
wifi:
|
|
ssid: $wifi_ssid
|
|
password: $wifi_password
|
|
|
|
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
|
ap:
|
|
ssid: "$name_of_board Fallback Hotspot"
|
|
password: "PZe2PJENtBiu"
|
|
|
|
manual_ip:
|
|
static_ip: $ip_addr
|
|
gateway: 172.23.23.1
|
|
dns1: 172.23.23.1
|
|
subnet: 255.255.255.0
|
|
|
|
on_connect:
|
|
- script.execute: refresh_access_machines
|
|
|
|
captive_portal:
|
|
|
|
spi:
|
|
clk_pin: GPIO14
|
|
mosi_pin: GPIO13
|
|
miso_pin: GPIO12
|
|
|
|
http_request:
|
|
useragent: esphome
|
|
timeout: 2s
|
|
id: http_request_data
|
|
|
|
globals:
|
|
- id: vault_api_token
|
|
type: std::string
|
|
restore_value: no
|
|
- id: rfid_tag
|
|
type: std::string
|
|
restore_value: no
|
|
- id: access_allowed
|
|
type: bool
|
|
restore_value: no
|
|
initial_value: 'false'
|
|
- id: access_cache
|
|
type: unsigned int[24]
|
|
restore_value: yes
|
|
initial_value: '{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}'
|
|
|
|
script:
|
|
- id: check_access
|
|
then:
|
|
- if:
|
|
condition:
|
|
lambda: |-
|
|
int rfid_value = decode_token(id(rfid_tag));
|
|
for (int i = 0; i < 24; i++) {
|
|
if (id(access_cache)[i] == rfid_value) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
then:
|
|
- script.execute: toggle_switch
|
|
- script.wait: toggle_switch
|
|
- if: # set LED to new switch state
|
|
condition:
|
|
switch.is_on: mlock_${name_of_board}_switch
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% }
|
|
else:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
else:
|
|
- script.execute: check_access_machines
|
|
- id: check_access_machines
|
|
mode: queued
|
|
then:
|
|
- lambda: |-
|
|
id(access_allowed) = false;
|
|
- http_request.get:
|
|
url: !lambda |-
|
|
return ((std::string) "https://machines.ctdo.de/machine/mlock-$name_of_board");
|
|
verify_ssl: false
|
|
headers:
|
|
Authorization: !lambda return "Bearer $machines_token";
|
|
on_response:
|
|
then:
|
|
- if:
|
|
condition:
|
|
lambda: 'return status_code == 200;'
|
|
then: # when found, check if machine is allowed, turn on output or blink LED red
|
|
- lambda: |-
|
|
std::string response = id(http_request_data).get_string();
|
|
id(process_machines_response)->execute(response);
|
|
DynamicJsonDocument doc(2048);
|
|
deserializeJson(doc, response);
|
|
unsigned int rfid_value = decode_token(id(rfid_tag));
|
|
for (JsonVariant elem : doc.as<JsonArray>()) {
|
|
std::string received_token = elem.as<std::string>();
|
|
int received_value = decode_token(received_token);
|
|
if (rfid_value == received_value) {
|
|
id(access_allowed) = true;
|
|
break;
|
|
}
|
|
}
|
|
- if:
|
|
condition:
|
|
lambda: 'return id(access_allowed);'
|
|
then:
|
|
- script.execute: toggle_switch
|
|
- script.execute:
|
|
id: cache_token
|
|
token: !lambda return id(rfid_tag);
|
|
- script.wait: toggle_switch
|
|
else:
|
|
- repeat:
|
|
count: 3
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
- delay: 0.1s
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% }
|
|
- delay: 0.1s
|
|
else: # could not fetch machine config, so blink LED
|
|
- repeat:
|
|
count: 5
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
- delay: 0.8s
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 0%, blue: 0% }
|
|
- delay: 0.8s
|
|
- if: # return LED to switch state
|
|
condition:
|
|
switch.is_on: mlock_${name_of_board}_switch
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 0%, green: 100%, blue: 0% }
|
|
else:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
- id: toggle_switch
|
|
mode: queued
|
|
then:
|
|
- if:
|
|
condition:
|
|
switch.is_on: mlock_${name_of_board}_switch
|
|
then:
|
|
- switch.turn_off: mlock_${name_of_board}_switch
|
|
- homeassistant.event:
|
|
event: esphome.mlock_locked
|
|
data:
|
|
tag: !lambda return id(rfid_tag);
|
|
machine: ${name_of_board}
|
|
else:
|
|
- switch.turn_on: mlock_${name_of_board}_switch
|
|
- homeassistant.event:
|
|
event: esphome.mlock_unlocked
|
|
data:
|
|
tag: !lambda return id(rfid_tag);
|
|
machine: ${name_of_board}
|
|
- text.set:
|
|
id: ${name_of_board}_letzte_entsperrung
|
|
value: !lambda return id(rfid_tag);
|
|
- id: cache_token
|
|
mode: queued
|
|
parameters:
|
|
token: string
|
|
then:
|
|
- lambda: |-
|
|
ESP_LOGI("mlock", "Caching token: %s", token.c_str());
|
|
int rfid_value = decode_token(token);
|
|
int rfid_value_pos = 23;
|
|
// search the token in the list to keep the access_cache unique
|
|
for (int i = 0; i < 24; i++) {
|
|
if (id(access_cache)[i] == rfid_value) {
|
|
rfid_value_pos = i;
|
|
break;
|
|
}
|
|
}
|
|
// shift the existing entries down
|
|
for (int i = rfid_value_pos; i >= 1; i--) {
|
|
id(access_cache)[i] = id(access_cache)[i - 1];
|
|
}
|
|
// write the new token to the start
|
|
id(access_cache)[0] = rfid_value;
|
|
- id: refresh_access_machines
|
|
mode: queued
|
|
then:
|
|
- logger.log:
|
|
tag: mlock
|
|
level: info
|
|
format: "Fetching config"
|
|
- http_request.get:
|
|
url: !lambda |-
|
|
return ((std::string) "https://machines.ctdo.de/machine/mlock-$name_of_board");
|
|
verify_ssl: false
|
|
headers:
|
|
Authorization: !lambda return "Bearer $machines_token";
|
|
on_response:
|
|
then:
|
|
- script.execute:
|
|
id: process_machines_response
|
|
response: !lambda return id(http_request_data).get_string();
|
|
- id: process_machines_response
|
|
mode: queued
|
|
parameters:
|
|
response: string
|
|
then:
|
|
- logger.log:
|
|
tag: mlock
|
|
level: info
|
|
format: "Allowed tokens: %s"
|
|
args: [ 'response.c_str()' ]
|
|
- lambda: |-
|
|
DynamicJsonDocument doc(2048);
|
|
deserializeJson(doc, response);
|
|
JsonArray array = doc.as<JsonArray>();
|
|
// invalidate cached tokens that are not allowed anymore
|
|
for (int i = 0; i < 24; i++) {
|
|
unsigned int cached_token = id(access_cache)[i];
|
|
if (cached_token == 0) {
|
|
break;
|
|
}
|
|
bool token_valid = false;
|
|
// search for cached token in the allowed list
|
|
for (JsonVariant elem : array) {
|
|
std::string received_token = elem.as<std::string>();
|
|
int received_value = decode_token(received_token);
|
|
if (cached_token == received_value) {
|
|
token_valid = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!token_valid) {
|
|
ESP_LOGI("mlock", "Purging removed token: %08X", id(access_cache)[i]);
|
|
// move remaining tokens up in the cache
|
|
for (int j = i; j < 23; j++) {
|
|
id(access_cache)[j] = id(access_cache)[j + 1];
|
|
}
|
|
id(access_cache)[23] = 0;
|
|
i--;
|
|
}
|
|
}
|
|
for (JsonVariant elem : array) {
|
|
std::string received_token = elem.as<std::string>();
|
|
int received_value = decode_token(received_token);
|
|
// append the token at the end of the cache in an empty slot if it is not in there yet
|
|
for (int i = 0; i < 24; i++) {
|
|
if (id(access_cache)[i] == received_value) {
|
|
break;
|
|
}
|
|
if (id(access_cache)[i] == 0) {
|
|
ESP_LOGI("mlock", "Pre-caching token: %X", received_value);
|
|
id(access_cache)[i] = received_value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc522_spi:
|
|
cs_pin: GPIO15
|
|
on_tag:
|
|
then:
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 60%, blue: 0% }
|
|
# small delay so the light can update its color
|
|
- delay: 15ms
|
|
# store the tag id into global variable
|
|
- lambda: |-
|
|
id(rfid_tag) = x;
|
|
- script.execute: check_access
|
|
- text.set:
|
|
id: ${name_of_board}_letzter_token
|
|
value: !lambda return id(rfid_tag);
|
|
|
|
# switch component for the output state
|
|
switch:
|
|
- platform: gpio
|
|
pin: D1
|
|
name: "Relais Output"
|
|
id: mlock_${name_of_board}_switch
|
|
internal: true # hide from Homeassistant, so no one can turn it on without Tag-Scanning
|
|
|
|
binary_sensor:
|
|
# sensor input for Turning Device off
|
|
- platform: gpio
|
|
pin:
|
|
number: D3
|
|
inverted: true
|
|
mode: INPUT_PULLUP
|
|
id: ${name_of_board}gpio_input_ausschalter
|
|
on_press:
|
|
- switch.turn_off: mlock_${name_of_board}_switch
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
|
|
# a template sensor for showing the current switch state (read only)
|
|
- platform: template
|
|
id: mlock_${name_of_board}_state_output
|
|
name: "${name_of_board} Status Ausgang"
|
|
publish_initial_state: true
|
|
lambda: |-
|
|
return id(mlock_${name_of_board}_switch).state;
|
|
|
|
# a button element for Homeassistant UI to allow turning off
|
|
button:
|
|
- platform: template
|
|
name: "${name_of_board} Ausschalter"
|
|
id: ${name_of_board}_btn_ausschalter
|
|
on_press:
|
|
- switch.turn_off: mlock_${name_of_board}_switch
|
|
- light.addressable_set: { id: status_led, red: 100%, green: 0%, blue: 0% }
|
|
- platform: template
|
|
name: "${name_of_board} Tokencache leeren"
|
|
id: ${name_of_board}_btn_tokencache_leeren
|
|
on_press:
|
|
- lambda: |-
|
|
for (int i = 0; i < 24; i++) {
|
|
id(access_cache)[i] = 0;
|
|
}
|
|
|
|
light:
|
|
- platform: neopixelbus
|
|
type: GRB
|
|
variant: WS2812
|
|
pin: D4
|
|
name: status_led
|
|
id: status_led
|
|
num_leds: 1
|
|
internal: true
|
|
|
|
text:
|
|
- platform: template
|
|
name: "$name_of_board Letzte Entsperung"
|
|
id: ${name_of_board}_letzte_entsperrung
|
|
optimistic: true
|
|
mode: text
|
|
- platform: template
|
|
name: "$name_of_board Zuletzt Gelesener Token"
|
|
id: ${name_of_board}_letzter_token
|
|
optimistic: true
|
|
mode: text
|