Compare commits
12 Commits
6f9b384caa
...
cbde498ae8
| Author | SHA1 | Date | |
|---|---|---|---|
| cbde498ae8 | |||
| 9feace9558 | |||
| 2a5496118b | |||
| f362b2ab77 | |||
| 7a8cd490d5 | |||
| 5a20d97084 | |||
| 8def0af08f | |||
| 348d8e1d03 | |||
| a078503a89 | |||
| bc57914131 | |||
| 3b01625f7d | |||
| 8cf4762a65 |
@@ -3,7 +3,7 @@
|
||||
- get age key from SSH
|
||||
```console
|
||||
curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=hetznercloud NIX_CHANNEL=nixos-24.05 bash 2>&1 | tee /tmp/infect.log
|
||||
nix-shell -p ssh-to-age --run 'ssh-keyscan example.com | ssh-to-age'
|
||||
nix-shell -p ssh-to-age --run 'ssh-keyscan install.cloonar.com | ssh-to-age'
|
||||
```
|
||||
- fix secrets files
|
||||
```console
|
||||
|
||||
340
esphome/hallway-light-switch.yaml
Normal file
340
esphome/hallway-light-switch.yaml
Normal file
@@ -0,0 +1,340 @@
|
||||
substitutions:
|
||||
# Default name
|
||||
name: "hallway-light-switch"
|
||||
# Default friendly name
|
||||
friendly_name: "Hallway Light Switch"
|
||||
# Allows ESP device to be automatically linked to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
|
||||
room: "Hallway"
|
||||
# Description as appears in ESPHome & top of webserver page
|
||||
device_description: "Hallway Light Switch"
|
||||
# Project Name
|
||||
project_name: "Athom Technology.Mini Relay V2"
|
||||
# Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
|
||||
project_version: "v2.0.4"
|
||||
# Restore the relay (GPO switch) upon reboot to state:
|
||||
light_restore_mode: RESTORE_DEFAULT_OFF
|
||||
# Set the update interval for sensors
|
||||
sensor_update_interval: 10s
|
||||
# Current Limit in Amps.
|
||||
current_limit : "10"
|
||||
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
|
||||
dns_domain: ".cloonar.smart"
|
||||
# Set timezone of the smart plug. Useful if the plug is in a location different to the HA server. Can be entered in unix Country/Area format (i.e. "Australia/Sydney")
|
||||
timezone: ""
|
||||
# Set the duration between the sntp service polling ntp.org servers for an update
|
||||
sntp_update_interval: 6h
|
||||
# Network time servers for your region, enter from lowest to highest priority. To use local servers update as per zones or countries at: https://www.ntppool.org/zone/@
|
||||
sntp_server_1: "0.pool.ntp.org"
|
||||
sntp_server_2: "1.pool.ntp.org"
|
||||
sntp_server_3: "2.pool.ntp.org"
|
||||
# Enables faster network connections, with last connected SSID being connected to and no full scan for SSID being undertaken
|
||||
wifi_fast_connect: "false"
|
||||
# Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
|
||||
log_level: "WARN"
|
||||
# Hide the ENERGY sensor that shows kWh consumed, but with no time period associated with it. Resets when device restarted and reflashed.
|
||||
hide_energy_sensor: "true"
|
||||
# Enable or disable the use of IPv6 networking on the device
|
||||
ipv6_enable: "false"
|
||||
|
||||
esphome:
|
||||
name: "${name}"
|
||||
friendly_name: "${friendly_name}"
|
||||
comment: "${device_description}"
|
||||
area: "${room}"
|
||||
name_add_mac_suffix: false
|
||||
min_version: 2024.5.0
|
||||
project:
|
||||
name: "${project_name}"
|
||||
version: "${project_version}"
|
||||
platformio_options:
|
||||
board_build.mcu: esp32c3
|
||||
board_build.variant: esp32c3
|
||||
board_build.flash_mode: dio
|
||||
|
||||
esp32:
|
||||
board: esp32-c3-devkitm-1
|
||||
flash_size: 4MB
|
||||
variant: ESP32C3
|
||||
framework:
|
||||
type: arduino
|
||||
version: recommended
|
||||
|
||||
preferences:
|
||||
flash_write_interval: 5min
|
||||
|
||||
api:
|
||||
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
|
||||
network:
|
||||
enable_ipv6: ${ipv6_enable}
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: ${dns_domain}
|
||||
|
||||
esp32_improv:
|
||||
authorizer: none
|
||||
|
||||
uart:
|
||||
rx_pin: GPIO20
|
||||
baud_rate: 4800
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: EVEN
|
||||
|
||||
globals:
|
||||
- id: total_energy
|
||||
type: float
|
||||
restore_value: yes
|
||||
initial_value: '0.0'
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Status"
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO3
|
||||
mode: INPUT_PULLUP
|
||||
inverted: true
|
||||
name: "Power Button"
|
||||
disabled_by_default: true
|
||||
on_multi_click:
|
||||
- timing:
|
||||
- ON for at most 1s
|
||||
- OFF for at least 0.2s
|
||||
then:
|
||||
- light.toggle: mini_relay
|
||||
- timing:
|
||||
- ON for at least 4s
|
||||
then:
|
||||
- button.press: Reset
|
||||
|
||||
- platform: gpio
|
||||
id: the_switch
|
||||
name: "Power Switch"
|
||||
pin:
|
||||
number: GPIO4
|
||||
mode: INPUT_PULLUP
|
||||
inverted: true
|
||||
on_multi_click:
|
||||
- timing:
|
||||
- ON for at most 1s
|
||||
then:
|
||||
- light.toggle: mini_relay
|
||||
|
||||
sensor:
|
||||
- platform: uptime
|
||||
name: "Uptime Sensor"
|
||||
id: uptime_sensor
|
||||
entity_category: diagnostic
|
||||
internal: true
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "WiFi Signal dB"
|
||||
id: wifi_signal_db
|
||||
update_interval: 60s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: copy
|
||||
source_id: wifi_signal_db
|
||||
name: "WiFi Signal Percent"
|
||||
filters:
|
||||
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
|
||||
unit_of_measurement: "Signal %"
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
- platform: cse7766
|
||||
id: athom_cse7766
|
||||
current:
|
||||
name: "Current"
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
- lambda: if (x < 0.060) return 0.0; else return x; #For the chip will report less than 3w power when no load is connected
|
||||
on_value_range:
|
||||
- above: ${current_limit}
|
||||
then:
|
||||
- light.turn_off: mini_relay
|
||||
|
||||
voltage:
|
||||
name: "Voltage"
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
|
||||
power:
|
||||
name: "Power"
|
||||
id: power_sensor
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
- lambda: if (x < 3.0) return 0.0; else return x; #For the chip will report less than 3w power when no load is connected
|
||||
|
||||
energy:
|
||||
name: "Energy"
|
||||
id: energy
|
||||
unit_of_measurement: kWh
|
||||
filters:
|
||||
- throttle: ${sensor_update_interval}
|
||||
# Multiplication factor from W to kW is 0.001
|
||||
- multiply: 0.001
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
static float previous_energy_value = 0.0;
|
||||
float current_energy_value = id(energy).state;
|
||||
id(total_energy) += current_energy_value - previous_energy_value;
|
||||
previous_energy_value = current_energy_value;
|
||||
id(total_energy_sensor).update();
|
||||
|
||||
apparent_power:
|
||||
name: "Apparent Power"
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
reactive_power:
|
||||
name: "Reactive Power"
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
power_factor:
|
||||
name: "Power Factor"
|
||||
filters:
|
||||
- throttle_average: ${sensor_update_interval}
|
||||
|
||||
- platform: template
|
||||
name: "Total Energy"
|
||||
id: total_energy_sensor
|
||||
unit_of_measurement: kWh
|
||||
device_class: "energy"
|
||||
state_class: "total_increasing"
|
||||
icon: "mdi:lightning-bolt"
|
||||
accuracy_decimals: 3
|
||||
lambda: |-
|
||||
return id(total_energy);
|
||||
update_interval: ${sensor_update_interval}
|
||||
|
||||
- platform: total_daily_energy
|
||||
name: "Total Energy Today"
|
||||
restore: true
|
||||
power_id: power_sensor
|
||||
unit_of_measurement: kWh
|
||||
accuracy_decimals: 3
|
||||
filters:
|
||||
- multiply: 0.001
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
id: relay_output
|
||||
pin: GPIO6
|
||||
|
||||
light:
|
||||
- platform: status_led
|
||||
id: led
|
||||
name: "Blue LED"
|
||||
disabled_by_default: true
|
||||
pin:
|
||||
number: GPIO7
|
||||
inverted: true
|
||||
|
||||
- platform: binary
|
||||
id: mini_relay
|
||||
output: relay_output
|
||||
name: "Mini Switch"
|
||||
restore_mode: ${light_restore_mode}
|
||||
on_turn_on:
|
||||
- light.turn_on: led
|
||||
on_turn_off:
|
||||
- light.turn_off: led
|
||||
|
||||
text_sensor:
|
||||
- platform: wifi_info
|
||||
ip_address:
|
||||
name: "IP Address"
|
||||
entity_category: diagnostic
|
||||
ssid:
|
||||
name: "Connected SSID"
|
||||
entity_category: diagnostic
|
||||
mac_address:
|
||||
name: "Mac Address"
|
||||
entity_category: diagnostic
|
||||
|
||||
# Creates a sensor showing when the device was last restarted
|
||||
- platform: template
|
||||
name: 'Last Restart'
|
||||
id: device_last_restart
|
||||
icon: mdi:clock
|
||||
entity_category: diagnostic
|
||||
# device_class: timestamp
|
||||
|
||||
# Creates a sensor of the uptime of the device, in formatted days, hours, minutes and seconds
|
||||
- platform: template
|
||||
name: "Uptime"
|
||||
entity_category: diagnostic
|
||||
lambda: |-
|
||||
int seconds = (id(uptime_sensor).state);
|
||||
int days = seconds / (24 * 3600);
|
||||
seconds = seconds % (24 * 3600);
|
||||
int hours = seconds / 3600;
|
||||
seconds = seconds % 3600;
|
||||
int minutes = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
if ( days > 3650 ) {
|
||||
return { "Starting up" };
|
||||
} else if ( days ) {
|
||||
return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else if ( hours ) {
|
||||
return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else if ( minutes ) {
|
||||
return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else {
|
||||
return { (String(seconds) +"s").c_str() };
|
||||
}
|
||||
icon: mdi:clock-start
|
||||
|
||||
time:
|
||||
- platform: sntp
|
||||
id: sntp_time
|
||||
# Define the timezone of the device
|
||||
timezone: "${timezone}"
|
||||
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
|
||||
update_interval: ${sntp_update_interval}
|
||||
# Set specific sntp servers to use
|
||||
servers:
|
||||
- "${sntp_server_1}"
|
||||
- "${sntp_server_2}"
|
||||
- "${sntp_server_3}"
|
||||
# Publish the time the device was last restarted
|
||||
on_time_sync:
|
||||
then:
|
||||
# Update last restart time, but only once.
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(device_last_restart).state == "";'
|
||||
then:
|
||||
- text_sensor.template.publish:
|
||||
id: device_last_restart
|
||||
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
|
||||
@@ -10,7 +10,6 @@ substitutions:
|
||||
sntp_server_1: "0.pool.ntp.org"
|
||||
sntp_server_2: "1.pool.ntp.org"
|
||||
sntp_server_3: "2.pool.ntp.org"
|
||||
log_level: "WARN"
|
||||
|
||||
esphome:
|
||||
name: "${name}"
|
||||
@@ -43,7 +42,7 @@ interval:
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
api.connected: # check if api connected
|
||||
api.connected:
|
||||
else:
|
||||
- light.turn_on:
|
||||
id: rgbww_light
|
||||
@@ -61,21 +60,31 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
|
||||
fast_connect: false
|
||||
domain: "${dns_domain}"
|
||||
|
||||
# Your hidden network
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
channel: 1
|
||||
hidden: true
|
||||
|
||||
captive_portal:
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.11
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
dns1: 8.8.8.8
|
||||
dns2: 1.1.1.1
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
# Fallback access point if Wi-Fi fails
|
||||
ap:
|
||||
ssid: "${name}_AP"
|
||||
password: "bulb_fallback_pw"
|
||||
ap_timeout: 2min # after 2 min of failed join, enable AP
|
||||
reboot_timeout: 5min # if still not joined after 5 min, reboot and retry
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -93,7 +102,7 @@ sensor:
|
||||
name: "WiFi Signal dB"
|
||||
id: wifi_signal_db
|
||||
update_interval: 60s
|
||||
entity_category: "diagnostic"
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: copy
|
||||
source_id: wifi_signal_db
|
||||
@@ -101,23 +110,7 @@ sensor:
|
||||
filters:
|
||||
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
|
||||
unit_of_measurement: "Signal %"
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
entity_category: diagnostic
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
@@ -171,55 +164,47 @@ text_sensor:
|
||||
name: "Mac Address"
|
||||
entity_category: diagnostic
|
||||
|
||||
# Creates a sensor showing when the device was last restarted
|
||||
- platform: template
|
||||
name: 'Last Restart'
|
||||
id: device_last_restart
|
||||
icon: mdi:clock
|
||||
entity_category: diagnostic
|
||||
# device_class: timestamp
|
||||
|
||||
# Creates a sensor of the uptime of the device, in formatted days, hours, minutes and seconds
|
||||
- platform: template
|
||||
name: "Uptime"
|
||||
entity_category: diagnostic
|
||||
lambda: |-
|
||||
int seconds = (id(uptime_sensor).state);
|
||||
int days = seconds / (24 * 3600);
|
||||
seconds = seconds % (24 * 3600);
|
||||
seconds %= (24 * 3600);
|
||||
int hours = seconds / 3600;
|
||||
seconds = seconds % 3600;
|
||||
seconds %= 3600;
|
||||
int minutes = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
if ( days > 3650 ) {
|
||||
seconds %= 60;
|
||||
if (days > 3650) {
|
||||
return { "Starting up" };
|
||||
} else if ( days ) {
|
||||
return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else if ( hours ) {
|
||||
return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else if ( minutes ) {
|
||||
return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
|
||||
} else if (days) {
|
||||
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
|
||||
} else if (hours) {
|
||||
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
|
||||
} else if (minutes) {
|
||||
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
|
||||
} else {
|
||||
return { (String(seconds) +"s").c_str() };
|
||||
return { (String(seconds) + "s").c_str() };
|
||||
}
|
||||
icon: mdi:clock-start
|
||||
|
||||
time:
|
||||
- platform: sntp
|
||||
id: sntp_time
|
||||
# Define the timezone of the device
|
||||
timezone: "${timezone}"
|
||||
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
|
||||
update_interval: ${sntp_update_interval}
|
||||
# Set specific sntp servers to use
|
||||
servers:
|
||||
- "${sntp_server_1}"
|
||||
- "${sntp_server_2}"
|
||||
- "${sntp_server_3}"
|
||||
# Publish the time the device was last restarted
|
||||
on_time_sync:
|
||||
then:
|
||||
# Update last restart time, but only once.
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(device_last_restart).state == "";'
|
||||
|
||||
@@ -61,21 +61,18 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
|
||||
captive_portal:
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
fast_connect: False
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
channel: 1
|
||||
hidden: True
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.12
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -104,21 +101,6 @@ sensor:
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: red_output
|
||||
|
||||
@@ -72,21 +72,18 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
|
||||
captive_portal:
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
fast_connect: False
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
hidden: True
|
||||
channel: 1
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.13
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -115,21 +112,6 @@ sensor:
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: red_output
|
||||
|
||||
@@ -72,21 +72,17 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
|
||||
captive_portal:
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
fast_connect: False
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
hidden: True
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.14
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -115,21 +111,6 @@ sensor:
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: red_output
|
||||
|
||||
@@ -72,21 +72,17 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
|
||||
captive_portal:
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
fast_connect: False
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
hidden: True
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.15
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -115,21 +111,6 @@ sensor:
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: red_output
|
||||
|
||||
@@ -72,21 +72,18 @@ api:
|
||||
ota:
|
||||
- platform: esphome
|
||||
|
||||
logger:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
fast_connect: True
|
||||
domain: .cloonar.smart
|
||||
|
||||
captive_portal:
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://athom-tech/athom-configs/athom-rgbww-light.yaml
|
||||
fast_connect: False
|
||||
networks:
|
||||
- ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
hidden: True
|
||||
channel: 1
|
||||
manual_ip:
|
||||
static_ip: 10.42.100.16
|
||||
gateway: 10.42.100.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
@@ -115,21 +112,6 @@ sensor:
|
||||
entity_category: "diagnostic"
|
||||
device_class: ""
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "Restart"
|
||||
entity_category: config
|
||||
|
||||
- platform: factory_reset
|
||||
name: "Factory Reset"
|
||||
id: Reset
|
||||
entity_category: config
|
||||
|
||||
- platform: safe_mode
|
||||
name: "Safe Mode"
|
||||
internal: false
|
||||
entity_category: config
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: red_output
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
./modules/networking.nix
|
||||
./modules/setupnetwork.nix
|
||||
./modules/firewall.nix
|
||||
./modules/dhcp4.nix
|
||||
./modules/unbound.nix
|
||||
# ./modules/dhcp4.nix
|
||||
# ./modules/unbound.nix
|
||||
|
||||
./modules/dnsmasq.nix
|
||||
./modules/avahi.nix
|
||||
./modules/openconnect.nix
|
||||
./modules/wireguard.nix
|
||||
@@ -33,7 +35,7 @@
|
||||
# ./modules/vscode-server.nix # Add VS Code Server microvm
|
||||
|
||||
./modules/ai-mailer.nix
|
||||
./modules/wazuh.nix
|
||||
# ./modules/wazuh.nix
|
||||
|
||||
# web
|
||||
./modules/web
|
||||
@@ -52,7 +54,8 @@
|
||||
./modules/deconz.nix
|
||||
# ./modules/mopidy.nix
|
||||
# ./modules/mosquitto.nix
|
||||
./modules/snapserver.nix
|
||||
# ./modules/snapserver.nix
|
||||
./modules/lms.nix
|
||||
|
||||
# gaming
|
||||
# ./modules/palworld.nix
|
||||
|
||||
160
hosts/fw/modules/dnsmasq.nix
Normal file
160
hosts/fw/modules/dnsmasq.nix
Normal file
@@ -0,0 +1,160 @@
|
||||
{ config, ... }: {
|
||||
services.resolved.enable = false;
|
||||
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
settings = {
|
||||
port = "53";
|
||||
bind-interfaces = true; # force dnsmasq to bind immediately
|
||||
expand-hosts = true;
|
||||
|
||||
log-dhcp = true;
|
||||
|
||||
server = [
|
||||
"/epicenter.works/10.50.60.1"
|
||||
"/akvorrat.at/10.50.60.1"
|
||||
"9.9.9.9"
|
||||
"149.112.112.11"
|
||||
];
|
||||
|
||||
interface = [
|
||||
"lan"
|
||||
"server"
|
||||
"infrastructure"
|
||||
"multimedia"
|
||||
"guest"
|
||||
"smart"
|
||||
];
|
||||
|
||||
domain = [
|
||||
"cloonar.com,lan"
|
||||
"cloonar.com,server"
|
||||
"cloonar.com,infrastructure"
|
||||
"cloonar.multimedia,multimedia"
|
||||
"cloonar.smart,smart"
|
||||
"cloonar.guest,guest"
|
||||
];
|
||||
|
||||
dhcp-option = [
|
||||
"lan,15,cloonar.com" # domain name
|
||||
"lan,3,${config.networkPrefix}.96.1" # Gateway
|
||||
"lan,6,${config.networkPrefix}.96.1" # DNS
|
||||
"server,15,cloonar.com"
|
||||
"server,3,${config.networkPrefix}.97.1"
|
||||
"server,6,${config.networkPrefix}.97.1"
|
||||
"infrastructure,15,cloonar.com"
|
||||
"infrastructure,3,${config.networkPrefix}.101.1"
|
||||
"infrastructure,6,${config.networkPrefix}.101.1"
|
||||
"multimedia,15,cloonar.multimedia"
|
||||
"multimedia,3,${config.networkPrefix}.99.1"
|
||||
"multimedia,6,${config.networkPrefix}.99.1"
|
||||
"smart,15,cloonar.smart"
|
||||
"smart,3,${config.networkPrefix}.100.1"
|
||||
"smart,6,${config.networkPrefix}.100.1"
|
||||
"guest,15,cloonar.guest"
|
||||
"guest,3,${config.networkPrefix}.254.1"
|
||||
"guest,6,9.9.9.9"
|
||||
];
|
||||
|
||||
dhcp-range = [
|
||||
"lan,${config.networkPrefix}.96.100,${config.networkPrefix}.96.200,24h"
|
||||
"server,${config.networkPrefix}.97.100,${config.networkPrefix}.97.200,24h"
|
||||
"infrastructure,${config.networkPrefix}.101.100,${config.networkPrefix}.101.200,24h"
|
||||
"multimedia,${config.networkPrefix}.99.100,${config.networkPrefix}.99.200,24h"
|
||||
"smart,${config.networkPrefix}.100.100,${config.networkPrefix}.100.200,24h"
|
||||
"guest,${config.networkPrefix}.254.100,${config.networkPrefix}.254.200,24h"
|
||||
];
|
||||
|
||||
dhcp-host = [
|
||||
"30:05:5c:56:62:37,${config.networkPrefix}.96.100,brn30055c566237"
|
||||
"24:df:a7:b1:1b:74,${config.networkPrefix}.96.101,rmproplus-b1-1b-74"
|
||||
|
||||
"1a:c4:04:6e:29:bd,${config.networkPrefix}.97.2,omada"
|
||||
"02:00:00:00:00:03,${config.networkPrefix}.97.5,web-02"
|
||||
"02:00:00:00:00:04,${config.networkPrefix}.97.6,matrix"
|
||||
"ea:db:d4:c1:18:ba,${config.networkPrefix}.97.50,git"
|
||||
"c2:4f:64:dd:13:0c,${config.networkPrefix}.97.20,home-assistant"
|
||||
"1a:c4:04:6e:29:02,${config.networkPrefix}.101.25,deconz"
|
||||
|
||||
"c4:a7:2b:c7:ea:30,${config.networkPrefix}.99.10,metz"
|
||||
"f0:2f:9e:d4:3b:21,${config.networkPrefix}.99.11,firetv-living"
|
||||
"e4:2a:ac:32:3f:79,${config.networkPrefix}.99.13,xbox"
|
||||
"f0:2f:9e:c1:74:72,${config.networkPrefix}.99.21,firetv-bedroom"
|
||||
"30:05:5c:56:62:37,${config.networkPrefix}.99.100,brn30055c566237"
|
||||
|
||||
"fc:ee:28:03:63:e9,${config.networkPrefix}.100.148,k1c"
|
||||
"cc:50:e3:bc:27:64,${config.networkPrefix}.100.112,Nuki_Bridge_1A753F72"
|
||||
"34:6f:24:f3:af:ad,${config.networkPrefix}.100.137,daikin86604"
|
||||
"34:6f:24:c1:f8:54,${config.networkPrefix}.100.139,daikin53800"
|
||||
];
|
||||
|
||||
address = [
|
||||
"/fw.cloonar.com/${config.networkPrefix}.97.1"
|
||||
"/omada.cloonar.com/${config.networkPrefix}.97.2"
|
||||
"/pc.cloonar.com/${config.networkPrefix}.96.5"
|
||||
"/home-assistant.cloonar.com/${config.networkPrefix}.97.20"
|
||||
"/mopidy.cloonar.com/${config.networkPrefix}.97.21"
|
||||
"/snapcast.cloonar.com/${config.networkPrefix}.97.21"
|
||||
"/git.cloonar.com/${config.networkPrefix}.97.50"
|
||||
"/feeds.cloonar.com/188.34.191.144"
|
||||
|
||||
"/stage.wsw.at/10.254.235.22"
|
||||
"/prod.wsw.at/10.254.217.23"
|
||||
"/piwik.wohnservice-wien.at/10.254.240.109"
|
||||
"/wohnberatung-wien.at/10.254.240.109"
|
||||
"/wohnpartner-wien.at/10.254.240.109"
|
||||
"/wohnservice-wien.at/10.254.240.109"
|
||||
"/mieterhilfe.at/10.254.240.109"
|
||||
"/wienbautvor.at/10.254.240.109"
|
||||
"/wienwohntbesser.at/10.254.240.109"
|
||||
"/a.stage.wohnberatung-wien.at/10.254.240.110"
|
||||
"/a.stage.wohnpartner-wien.at/10.254.240.110"
|
||||
"/a.stage.wohnservice-wien.at/10.254.240.110"
|
||||
"/a.stage.mieterhilfe.at/10.254.240.110"
|
||||
"/a.stage.wienbautvor.at/10.254.240.110"
|
||||
"/a.stage.wienwohntbesser.at/10.254.240.110"
|
||||
"/b.stage.wohnberatung-wien.at/10.254.240.110"
|
||||
"/b.stage.wohnpartner-wien.at/10.254.240.110"
|
||||
"/b.stage.wohnservice-wien.at/10.254.240.110"
|
||||
"/b.stage.mieterhilfe.at/10.254.240.110"
|
||||
"/b.stage.wienbautvor.at/10.254.240.110"
|
||||
"/b.stage.wienwohntbesser.at/10.254.240.110"
|
||||
|
||||
"/web.hilgenberg-gmbh.de/91.107.197.169"
|
||||
# gaming
|
||||
"/foundry-vtt.cloonar.com/${config.networkPrefix}.97.5"
|
||||
|
||||
"/deconz.cloonar.multimedia/${config.networkPrefix}.97.22"
|
||||
|
||||
"/ddl-warez.to/172.67.184.30"
|
||||
"/cdnjs.cloudflare.com/104.17.24.14"
|
||||
|
||||
# esphome devices
|
||||
"/livingroom-bulb-1.cloonar.smart/${config.networkPrefix}.100.11"
|
||||
"/livingroom-bulb-2.cloonar.smart/${config.networkPrefix}.100.12"
|
||||
"/livingroom-bulb-3.cloonar.smart/${config.networkPrefix}.100.13"
|
||||
"/livingroom-bulb-4.cloonar.smart/${config.networkPrefix}.100.14"
|
||||
"/livingroom-bulb-5.cloonar.smart/${config.networkPrefix}.100.15"
|
||||
"/livingroom-bulb-6.cloonar.smart/${config.networkPrefix}.100.16"
|
||||
|
||||
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.21"
|
||||
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.22"
|
||||
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.23"
|
||||
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.24"
|
||||
|
||||
"/hallway-bulb-0.cloonar.smart/${config.networkPrefix}.100.31"
|
||||
"/hallway-bulb-0.cloonar.smart/${config.networkPrefix}.100.32"
|
||||
|
||||
"/bath-bulb-0.cloonar.smart/${config.networkPrefix}.100.41"
|
||||
"/bath-bulb-0.cloonar.smart/${config.networkPrefix}.100.42"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.dnsmasq = {
|
||||
requires = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedUDPPorts = [ 53 67 ];
|
||||
}
|
||||
@@ -8,6 +8,18 @@
|
||||
"cloonar-fw" = {
|
||||
family = "inet";
|
||||
content = ''
|
||||
chain snap-qos-raw {
|
||||
type filter hook prerouting priority raw; policy accept;
|
||||
tcp dport 1704 counter mark set 10 comment "Mark Snapcast traffic"
|
||||
tcp dport 3483 counter mark set 10 comment "Mark Squezelite traffic"
|
||||
udp dport 3483 counter mark set 10 comment "Mark Squezelite traffic"
|
||||
}
|
||||
|
||||
chain snap-qos-mangle {
|
||||
type filter hook postrouting priority mangle + 10; policy accept;
|
||||
mark 10 counter ip dscp set cs3 comment "Tag Snapcast with CS3"
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority 100; policy accept;
|
||||
}
|
||||
@@ -22,6 +34,7 @@
|
||||
type filter hook input priority filter; policy drop;
|
||||
iifname "lo" accept comment "trusted interfaces"
|
||||
iifname "lan" counter accept comment "Spice"
|
||||
iifname { "server", "vserver", "vm-*", "lan", "wg_cloonar" } counter accept comment "allow trusted to router"
|
||||
ct state vmap { invalid : drop, established : accept, related : accept, new : jump input-allow, untracked : jump input-allow }
|
||||
tcp flags syn / fin,syn,rst,ack log prefix "refused connection: " level info
|
||||
}
|
||||
@@ -34,11 +47,14 @@
|
||||
iifname "lan" tcp dport 5931 counter accept comment "Spice"
|
||||
iifname { "server", "vserver", "vm-*", "lan", "wg_cloonar" } counter accept comment "allow trusted to router"
|
||||
iifname { "multimedia", "smart", "infrastructure", "podman0", "setup" } udp dport { 53, 5353 } counter accept comment "DNS"
|
||||
iifname { "multimedia", "smart", "infrastructure", "server", "lan", "guest" } udp dport { 67 } counter accept comment "DHCP"
|
||||
iifname { "wan", "multimedia" } icmp type { echo-request, destination-unreachable, time-exceeded } counter accept comment "Allow select ICMP"
|
||||
|
||||
# Accept mDNS for avahi reflection
|
||||
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 tcp dport { llmnr } counter accept
|
||||
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 udp dport { mdns, llmnr } counter accept
|
||||
iifname "server" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "Avahi mDNS"
|
||||
iifname "lan" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "Avahi mDNS"
|
||||
|
||||
# Allow all returning traffic
|
||||
ct state { established, related } counter accept
|
||||
@@ -79,10 +95,24 @@
|
||||
# multimedia airplay
|
||||
iifname "multimedia" oifname { "lan" } counter accept
|
||||
iifname "multimedia" oifname "server" tcp dport { 1704, 1705 } counter accept
|
||||
iifname "multimedia" oifname "server" tcp dport { 3483, 9000 } counter accept
|
||||
iifname "multimedia" oifname "server" udp dport { 3483 } counter accept
|
||||
iifname "multimedia" oifname "server" icmp type { echo-request, destination-unreachable, time-exceeded } counter accept comment "Allow select ICMP"
|
||||
iifname "lan" oifname "server" udp dport { 5000, 5353, 6001 - 6011 } counter accept
|
||||
# avahi
|
||||
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 oifname { "lan" } counter accept
|
||||
|
||||
# Allow Chromecast
|
||||
iifname "lan" oifname "server" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "mDNS query LAN→Server"
|
||||
iifname "server" oifname "lan" udp sport 5353 ip saddr 224.0.0.251 counter accept comment "mDNS response Server→LAN"
|
||||
iifname "lan" oifname "server" tcp dport 9881 counter accept comment "chromecast"
|
||||
|
||||
# SSDP / UPnP discovery if needed
|
||||
iifname { "lan", "server" } oifname { "server", "lan" } \
|
||||
udp dport 1900 ip daddr 239.255.255.250 counter accept comment "SSDP query"
|
||||
iifname { "lan", "server" } oifname { "server", "lan" } \
|
||||
udp sport 1900 ip saddr 239.255.255.250 counter accept comment "SSDP response"
|
||||
|
||||
# smart home coap
|
||||
iifname "smart" oifname "server" ip daddr ${config.networkPrefix}.97.20/32 udp dport { 5683 } counter accept
|
||||
iifname "smart" oifname "server" ip daddr ${config.networkPrefix}.97.20/32 tcp dport { 1883 } counter accept
|
||||
|
||||
@@ -421,21 +421,62 @@
|
||||
"light.bathroom_bulb_2"
|
||||
];
|
||||
}
|
||||
{
|
||||
platform = "switch";
|
||||
name = "Hallway Switch";
|
||||
entity_id = "switch.hallway";
|
||||
}
|
||||
{
|
||||
platform = "group";
|
||||
name = "Hallway Lights";
|
||||
all = true;
|
||||
entities = [
|
||||
"light.hallway_switch"
|
||||
"light.hallway_light_switch_mini_switch"
|
||||
"light.hallway_bulb_1"
|
||||
"light.hallway_bulb_2"
|
||||
];
|
||||
}
|
||||
{
|
||||
platform = "template";
|
||||
lights = {
|
||||
hallway_group_proxy = {
|
||||
friendly_name = "Hallway Lights (Proxy)";
|
||||
# follow the real group’s on/off state
|
||||
value_template = "{{ is_state('light.hallway_lights','on') }}";
|
||||
turn_on = {
|
||||
service = "light.turn_on";
|
||||
data = { entity_id = "light.hallway_lights"; };
|
||||
};
|
||||
turn_off = {
|
||||
service = "light.turn_off";
|
||||
data = { entity_id = "light.hallway_lights"; };
|
||||
};
|
||||
# brightness support
|
||||
set_level = {
|
||||
service = "light.turn_on";
|
||||
data_template = {
|
||||
entity_id = "light.hallway_lights";
|
||||
brightness = "{{ brightness }}";
|
||||
};
|
||||
};
|
||||
# color temperature support (if you have CT-capable bulbs)
|
||||
set_temperature = {
|
||||
service = "light.turn_on";
|
||||
data_template = {
|
||||
entity_id = "light.hallway_lights";
|
||||
color_temp = "{{ color_temp }}";
|
||||
};
|
||||
};
|
||||
# RGB color support
|
||||
set_color = {
|
||||
service = "light.turn_on";
|
||||
data_template = {
|
||||
entity_id = "light.hallway_lights";
|
||||
rgb_color = [ "{{ red }}" "{{ green }}" "{{ blue }}" ];
|
||||
};
|
||||
};
|
||||
# always report as “available”
|
||||
availability_template = "true";
|
||||
# declare which color modes you need
|
||||
supported_color_modes = [ "brightness" "color_temp" "rgb" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
platform = "switch";
|
||||
name = "Toilet Switch";
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
let
|
||||
devices = [
|
||||
"device_tracker.dominiks_iphone"
|
||||
"device_tracker.dominiks_mp01"
|
||||
];
|
||||
in {
|
||||
services.home-assistant.extraComponents = [
|
||||
"nuki"
|
||||
];
|
||||
@@ -9,9 +14,7 @@
|
||||
mode = "restart";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = [
|
||||
"device_tracker.dominiks_iphone"
|
||||
];
|
||||
entity_id = devices;
|
||||
from = "not_home";
|
||||
to = "home";
|
||||
};
|
||||
|
||||
@@ -494,6 +494,12 @@
|
||||
entity_id = "script.turn_on_tv";
|
||||
};
|
||||
}
|
||||
{
|
||||
service = "media_player.turn_off";
|
||||
target = {
|
||||
entity_id = "media_player.marantz_sr6015";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
services.home-assistant.extraComponents = [ "squeezebox" ];
|
||||
services.home-assistant.config = {
|
||||
"automation toilet music" = {
|
||||
alias = "toilet music";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "light.toilett_lights";
|
||||
entity_id = "light.toilet_switch";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
@@ -13,10 +14,52 @@
|
||||
entity_id = "media_player.music_toilet_snapcast_client";
|
||||
};
|
||||
data = {
|
||||
is_volume_muted = "{{ trigger.to_state.state == 'off' }}";
|
||||
is_volume_muted = "{{ trigger.to_state.state != 'on' }}";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation bathroom music" = {
|
||||
alias = "bathroom music";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "light.bathroom_switch";
|
||||
};
|
||||
action = [
|
||||
{
|
||||
service = "media_player.volume_mute";
|
||||
target = {
|
||||
entity_id = "media_player.music_bathroom_snapcast_client";
|
||||
};
|
||||
data = {
|
||||
is_volume_muted = "{{ trigger.to_state.state != 'on' }}";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
"automation piano" = {
|
||||
alias = "piano";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "media_player.music_piano_snapcast_client";
|
||||
attribute = "is_volume_muted";
|
||||
};
|
||||
condition = [
|
||||
{
|
||||
condition = "template";
|
||||
value_template = "{{ trigger.from_state.state != 'unavailable' }}";
|
||||
}
|
||||
{
|
||||
condition = "template";
|
||||
value_template = "{{ state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == true or state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == false }}";
|
||||
}
|
||||
];
|
||||
action = {
|
||||
service = "switch.turn_on";
|
||||
target = {
|
||||
entity_id = "switch.piano_switch_power";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,31 +1,5 @@
|
||||
{
|
||||
services.home-assistant = {
|
||||
extraComponents = [ "snapcast" ];
|
||||
config = {
|
||||
"automation piano" = {
|
||||
alias = "piano";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "media_player.music_piano_snapcast_client";
|
||||
attribute = "is_volume_muted";
|
||||
};
|
||||
condition = [
|
||||
{
|
||||
condition = "template";
|
||||
value_template = "{{ trigger.from_state.state != 'unavailable' }}";
|
||||
}
|
||||
{
|
||||
condition = "template";
|
||||
value_template = "{{ state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == true or state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == false }}";
|
||||
}
|
||||
];
|
||||
action = {
|
||||
service = "switch.turn_on";
|
||||
target = {
|
||||
entity_id = "switch.piano_switch_power";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
88
hosts/fw/modules/lms.nix
Normal file
88
hosts/fw/modules/lms.nix
Normal file
@@ -0,0 +1,88 @@
|
||||
{ pkgs, config, lib, python3Packages, ... }:
|
||||
|
||||
let
|
||||
lmsDomain = "lms.cloonar.com";
|
||||
networkPrefix = config.networkPrefix;
|
||||
in
|
||||
{
|
||||
security.acme.certs."${lmsDomain}" = {
|
||||
group = "nginx";
|
||||
};
|
||||
|
||||
sops.secrets.lms-spotify = { };
|
||||
|
||||
containers.lms = {
|
||||
autoStart = true;
|
||||
ephemeral = false;
|
||||
privateNetwork = true;
|
||||
hostBridge = "server";
|
||||
|
||||
hostAddress = "${networkPrefix}.97.2";
|
||||
localAddress = "${networkPrefix}.97.21/24";
|
||||
|
||||
extraFlags = [ "--capability=CAP_NET_ADMIN" ];
|
||||
|
||||
bindMounts = {
|
||||
"/var/lib/acme/lms/" = {
|
||||
hostPath = config.security.acme.certs.${lmsDomain}.directory;
|
||||
isReadOnly = true;
|
||||
};
|
||||
"/run/secrets/lms-spotify" = {
|
||||
hostPath = config.sops.secrets.lms-spotify.path;
|
||||
};
|
||||
};
|
||||
|
||||
config = { pkgs, lib, config, ... }:
|
||||
let
|
||||
in
|
||||
{
|
||||
networking = {
|
||||
hostName = "lms";
|
||||
useHostResolvConf = false;
|
||||
defaultGateway = {
|
||||
address = "${networkPrefix}.97.1";
|
||||
interface = "eth0";
|
||||
};
|
||||
nameservers = [ "${networkPrefix}.97.1" ];
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
slimserver # Logitech/Lyrion Media Server
|
||||
];
|
||||
|
||||
services.slimserver = {
|
||||
enable = true;
|
||||
package = pkgs.slimserver;
|
||||
};
|
||||
|
||||
# make LMS discoverable via mDNS/Avahi
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
publish.enable = true;
|
||||
publish.userServices = true;
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."${lmsDomain}" = {
|
||||
sslCertificate = "/var/lib/acme/lms/fullchain.pem";
|
||||
sslCertificateKey = "/var/lib/acme/lms/key.pem";
|
||||
sslTrustedCertificate = "/var/lib/acme/lms/chain.pem";
|
||||
forceSSL = true;
|
||||
extraConfig = "proxy_buffering off;";
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect http:// https://;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
'';
|
||||
};
|
||||
|
||||
system.stateVersion = "23.05";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -261,6 +261,10 @@ in {
|
||||
enable = true;
|
||||
path = with pkgs; [ unbound inotify-tools ];
|
||||
script = ''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# readFile and readFileUnique as before…
|
||||
function readFile() {
|
||||
if [[ "''\$2" == "A" ]] ; then
|
||||
cat "''\$1" | tail -n +2 | while IFS=, read -r address hwaddr client_id valid_lifetime expire subnet_id fqdn_fwd fqdn_rev hostname state user_context
|
||||
@@ -315,17 +319,25 @@ in {
|
||||
done
|
||||
}
|
||||
|
||||
function syncFile() {
|
||||
# readFileUnique "''\$1" "''\$2"
|
||||
while true; do
|
||||
readFileUnique "''\$1" "''\$2"
|
||||
sleep 10
|
||||
function syncLeases() {
|
||||
# 1) nuke all of our old lease records from unbound
|
||||
unbound-control list_local_data \
|
||||
| grep -E 'cloonar\.(com|multimedia|smart)|ip4\.arpa|in-addr\.arpa' \
|
||||
| while read -r name type data; do
|
||||
unbound-control local_data_remove "$name" "$type" "$data" \
|
||||
> /dev/null 2>&1
|
||||
done
|
||||
|
||||
# 2) re-push every current lease
|
||||
readFileUnique "/var/lib/kea/dhcp4.leases" A
|
||||
# if you need IPv6:
|
||||
# readFileUnique "/var/lib/kea/dhcp6.leases" AAAA
|
||||
}
|
||||
|
||||
syncFile "/var/lib/kea/dhcp4.leases" A &
|
||||
# syncFile "/var/lib/kea/dhcp6.leases" AAAA &
|
||||
wait
|
||||
while true; do
|
||||
syncLeases
|
||||
sleep 10
|
||||
done
|
||||
'';
|
||||
wants = [ "network-online.target" "unbound.service" ];
|
||||
after = [ "network-online.target" "unbound.service" ];
|
||||
|
||||
@@ -17,6 +17,7 @@ matrix-shared-secret: ENC[AES256_GCM,data:67imd3m6WBeGP/5Msmjy8B6sP983jMyWzRIzWg
|
||||
palworld: ENC[AES256_GCM,data:rdqChPt4gSJHS1D60+HJ+4m5mg35JbC+pOmevK21Y95QyAIeyBLVGhRYlOaUcqdZM2e4atyTTSf6z4nHsm539ddCbW7J2DCdF5PQkrAGDmmdTVq+jyJAT8gTrbXXCglT1wvFYY5dbf2NKA4ASJIA8bdVNuwRZU0CtFiishzLuc9m8ZcGCNwQ/+xkMZgkUAHYRlEJAZyMpXR6KkFftiR05JRAFczD4N7GXPPe+vyvgXg7QBGtf20Qd4SGBUw0zI/SNTRmifHUuc4Z6+Fe9JHgvTc3uFcTMVnty0fEuL+a29liaVdAFq8BnqJfc5CNV401ZSUeMbG41lCn1cegP/WChs9J6HXNrhWDgiXa6ln++NoKcfOHIfZVbYOCoOxFR6+YWeBU2+sHmdwI9j5XQf5Ly2hmg12j0Ds2Cn8k4PG5aQP+HT2bedqyxwSt6fi97A0Osnh4ig7+DzYAjSNLewbYLzVdK39VdvB9hqLto+yFS3gAaeYOHwPwtqa+COI85c55lHiyKHlSwPhBqYaaiDu00lQTUzq9R5vz6F/l+T3bUjuna5RryUu8yhnk5DyK834KycTOg4ETcZTqro6prfiEBxc+Utsc9JvEtZgwFv6fsVLOu7nHxuiYuvseZ4YA8LlYdwPJboMPO2XsuhwWtT1uz/rh2orH7/vsXvzA/kF8NFemWBEMVLYA8byC5ze8doiGDYp4T5AAf10nJB1ceQ==,iv:gs78fxhvo9KlTaR5nzs12/LdgPChSFPHD2k4VQp3ARo=,tag:lpWBOi9xh2cWkS+71KD/UQ==,type:str]
|
||||
ark: ENC[AES256_GCM,data:YYGyzoVIKI9Ac1zGOr0BEpd3fgBsvp1hSwAvfO07/EQdg8ufMWUkNvqNHDKN62ZK5A1NnY3JTA1p4gyZ4ryQeAOsbwqU1GSk2YKHFyPeEnpLz/Ml82KMsv7XPGXuKRXZ4v3UcLu0R8k1Q0gQsMWo4FjCs3FF5mVtJG/YWxxbCYHoBLJ/di5p0DgjuFgJBQknYBpuLzr+yIoeqEyN7XcGYAJO53trEJuOOxLILULifkqISHjZ66i5F1fHW0iUdRbmeWV4aOAeOrsQqXYv,iv:gJwV5ip84zHqpU0l0uESfWWOtcgihMvEEdLaeI+twcU=,tag:sy8udVQsKxV/jOqwhJmWAg==,type:str]
|
||||
firefox-sync: ENC[AES256_GCM,data:uAJAdyKAuXRuqCFl8742vIejU5RnAPpUxUFCC0s0QeXZR5oH2YOrDh+3vKUmckW4V1cIhSHoe+4+I4HuU5E73DDrJThfIzBEw+spo4HXwZf5KBtu3ujgX6/fSTlPWV7pEsDDsZ0y6ziKPADBDym8yEk0bU9nRedvTBUhVryo3aolzF/c+gJvdeDvKUYa8+8=,iv:yuvE4KG7z7Rp9ZNlLiJ2rh0keed3DuvrELzsfJu4+bs=,tag:HFo1A53Eva31NJ8fRE7TlA==,type:str]
|
||||
knot-tsig-key: ENC[AES256_GCM,data:H2jEkRSVSIJl1dSolAXj9uUmzD6eEh9zPpoajZLxfuuFt7/LJF8aCEHyk+Q=,iv:9aqywuaILYtejuZGd+Cy8oErrHIoL2XhL1g9HtcUn/o=,tag:K3SnVEXGC/NhlchU7OyA6Q==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
@@ -59,8 +60,8 @@ sops:
|
||||
WXJpUUxadERyYUExRFMzNzBXaUVET3cKG9ZwWy5YvTr/BAw/i+ZJos5trwRvaW5j
|
||||
eV/SHiEteZZtCuCVFAp3iolE/mJyu97nA2yFwWaLN86h+/xkOJsdqA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-03-01T22:14:10Z"
|
||||
mac: ENC[AES256_GCM,data:UWwjvi8jLNgu4l7ldMYtkAATm3y5+BSxbCuPN/e1OC4/3ULYJndqFLfTOMpqQbj2+uHo3onelK4f0MAJuSH0oUx58CclkNBBLE0RXafxbowa7kJtTNDfTboJNqH7rFmhGhqCtHAOOpKBuowqoOUHP5BtzZfucra0Q/pIJt5lma0=,iv:iJEW/mTbizioPSN8G+WqHSipx8P6VCDrVG/Cmk+MBUc=,tag:L4OkeKec5AZdCrpUrnqcOA==,type:str]
|
||||
lastmodified: "2025-05-01T20:36:09Z"
|
||||
mac: ENC[AES256_GCM,data:ZtXJcuwDpDlBl2xdRtMF1PwwqbW00Eps2ZZG5x4C2djAq+meXJCxKS9sNazQhMYFOqphQXe3JEhChykLxnJyWivY/Er1ig2sU6Ke1uVcfSP85B1/rpzhe/7QI+GBDWrkCk1O0xGKKj8fWt+Yv2MV8gw2XctdtJ9Md4imUhcK7zo=,iv:5NFH+7Z0alBiq/b94T40XJSCar2+BGaFB20z0Kc59fU=,tag:18n0tt17RNMyyE0eECH2kQ==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.9.4
|
||||
|
||||
@@ -25,7 +25,7 @@ in {
|
||||
./utils/modules/nur.nix
|
||||
./modules/appimage.nix
|
||||
./modules/sway/sway.nix
|
||||
./modules/printer.nix
|
||||
# ./modules/printer.nix
|
||||
# ./modules/cyberghost.nix
|
||||
./utils/modules/autoupgrade.nix
|
||||
./modules/puppeteer.nix
|
||||
|
||||
@@ -78,6 +78,7 @@ let
|
||||
"media.ffmpeg.vaapi.enabled" = true;
|
||||
"media.ffmpeg.vaapi-drm-display.enabled" = true;
|
||||
"gfx.webrender.all" = true;
|
||||
"xpinstall.signatures.required" = false;
|
||||
};
|
||||
|
||||
firefoxUserChrome = ''
|
||||
@@ -531,7 +532,7 @@ in
|
||||
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
package = pkgs.firefox.overrideAttrs (a: {
|
||||
package = pkgs.firefox-devedition.overrideAttrs (a: {
|
||||
postInstall = a.postInstall or "" + ''
|
||||
wrapProgram "$out/bin/firefox" \
|
||||
export MOZ_ENABLE_WAYLAND=1
|
||||
@@ -558,6 +559,11 @@ in
|
||||
icon = "fingerprint";
|
||||
id = 1;
|
||||
};
|
||||
"dating" = {
|
||||
color = "pink";
|
||||
icon = "circle";
|
||||
id = 5;
|
||||
};
|
||||
"cloonar technologies" = {
|
||||
color = "red";
|
||||
icon = "briefcase";
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
server_name = "code.cloonar.com";
|
||||
aliasgroup1 = "https://nextcloud.cloonar.com:443";
|
||||
aliasgroup2 = "https://cloud.cloonar.com:443";
|
||||
dictionaries = "en_US";
|
||||
# Hannes
|
||||
aliasgroup3 = "https://nx67898.your-storageshare.de:443";
|
||||
aliasgroup4 = "https://hs-cloud.cloonar.com:443";
|
||||
dictionaries = "en_GB en_US de_DE";
|
||||
extra_params = "--o:ssl.enable=false --o:ssl.termination=true";
|
||||
};
|
||||
extraOptions = [
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
enable = true;
|
||||
hostName = "nextcloud.cloonar.com";
|
||||
https = true;
|
||||
package = nextcloud30;
|
||||
package = pkgs.nextcloud31;
|
||||
# Instead of using pkgs.nextcloud27Packages.apps,
|
||||
# we'll reference the package version specified above
|
||||
extraApps = {
|
||||
|
||||
7
hosts/web-arm/modules/postfix.nix
Normal file
7
hosts/web-arm/modules/postfix.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ pkgs, ... }: {
|
||||
services.postfix = {
|
||||
enable = true;
|
||||
domain = "cloonar.com";
|
||||
hostname = "web-arm.cloonar.com";
|
||||
};
|
||||
}
|
||||
122
raspberry/picoreplayer.sh
Executable file
122
raspberry/picoreplayer.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Must be run as root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root. Try sudo $0 ..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default env file
|
||||
ENV_FILE="./.env"
|
||||
|
||||
# PiCorePlayer version to use
|
||||
PCP_VERSION="10.0.0"
|
||||
BASE_URL="https://repo.pcplayer.org/insitu/piCorePlayer${PCP_VERSION}"
|
||||
IMG_ZIP="piCorePlayer${PCP_VERSION}.img.xz"
|
||||
DOWNLOAD_URL="${BASE_URL}/${IMG_ZIP}"
|
||||
|
||||
# Print usage
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: sudo $0 --device <rpi-4|rpi-zero|rpi-zero-2> \
|
||||
--sdcard </dev/sdX> \
|
||||
[--env-file /path/to/.env]
|
||||
|
||||
--device Target board (rpi-4, rpi-zero, rpi-zero-2)
|
||||
--sdcard Device node of the SD card (e.g. /dev/sdb)
|
||||
--env-file File containing WIFI_SSID and WIFI_PSK (defaults to ./.env)
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse args
|
||||
DEVICE="" SDCARD=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--device) DEVICE="$2"; shift 2;;
|
||||
--sdcard) SDCARD="$2"; shift 2;;
|
||||
--env-file) ENV_FILE="$2"; shift 2;;
|
||||
-h|--help) usage;;
|
||||
*) echo "Unknown option: $1" >&2; usage;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate
|
||||
if [[ -z "$DEVICE" || -z "$SDCARD" ]]; then
|
||||
usage
|
||||
fi
|
||||
if [[ ! -b "$SDCARD" ]]; then
|
||||
echo "Error: $SDCARD is not a block device." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Error: env file '$ENV_FILE' not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Load Wi-Fi credentials
|
||||
source "$ENV_FILE"
|
||||
if [[ -z "${WIFI_SSID:-}" || -z "${WIFI_PSK:-}" ]]; then
|
||||
echo "Error: WIFI_SSID and WIFI_PSK must be set in $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Download if needed
|
||||
if [[ ! -f "$IMG_ZIP" ]]; then
|
||||
echo "Downloading $IMG_ZIP ..."
|
||||
wget -q --show-progress "$DOWNLOAD_URL"
|
||||
fi
|
||||
|
||||
# Flash image
|
||||
echo "Flashing $IMG_ZIP to $SDCARD (will overwrite everything!)"
|
||||
sync
|
||||
xzcat "$IMG_ZIP" | dd of="$SDCARD" bs=4M status=progress
|
||||
sync
|
||||
|
||||
# Determine partition suffixes (/dev/sdX1 vs /dev/mmcblk0p1)
|
||||
if [[ "$SDCARD" =~ [0-9]$ ]]; then
|
||||
PART1="${SDCARD}p1"; PART2="${SDCARD}p2"
|
||||
else
|
||||
PART1="${SDCARD}1"; PART2="${SDCARD}2"
|
||||
fi
|
||||
|
||||
# Mount partitions
|
||||
BOOT_MNT=$(mktemp -d)
|
||||
ROOT_MNT=$(mktemp -d)
|
||||
mount "$PART1" "$BOOT_MNT"
|
||||
mount "$PART2" "$ROOT_MNT"
|
||||
|
||||
# Create hidden Wi-Fi config on boot partition
|
||||
cat > "$BOOT_MNT/wpa_supplicant.conf" <<EOF
|
||||
ctrl_interface=/var/run/wpa_supplicant
|
||||
ctrl_interface_group=staff
|
||||
country=AT
|
||||
update_config=1
|
||||
|
||||
network={
|
||||
ssid="$WIFI_SSID"
|
||||
psk="$WIFI_PSK"
|
||||
scan_ssid=1
|
||||
key_mgmt=WPA-PSK
|
||||
auth_alg=OPEN
|
||||
}
|
||||
EOF
|
||||
|
||||
# If a Zero device, enable Hifiberry DAC+ and disable onboard audio
|
||||
if [[ "$DEVICE" == "rpi-zero" || "$DEVICE" == "rpi-zero-2" ]]; then
|
||||
cat >> "$BOOT_MNT/config.txt" <<EOF
|
||||
|
||||
# Hifiberry DAC+ overlay for Zero models
|
||||
dtoverlay=hifiberry-dacplus-std
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
umount "$BOOT_MNT" "$ROOT_MNT"
|
||||
rmdir "$BOOT_MNT" "$ROOT_MNT"
|
||||
|
||||
echo "Done! SD card is ready with PiCorePlayer ${PCP_VERSION} on $DEVICE,"
|
||||
echo "hidden Wi-Fi '$WIFI_SSID'."
|
||||
echo "Insert the SD card into the Pi and power it on."
|
||||
echo "You can now connect to the PiCorePlayer web interface at http://pcp.local"
|
||||
@@ -6,8 +6,8 @@ stdenv.mkDerivation rec {
|
||||
|
||||
src = fetchgit {
|
||||
url = "https://github.com/dpolakovics/bento.git";
|
||||
rev = "8d911a02dc9af222ffb5892bbddd4a3895893959";
|
||||
sha256 = "sha256-9R3glZcjc+t8LKvo5HOAo+HzXFQ6GOtzehJpb7GjmYM=";
|
||||
rev = "73092673b194fd734d782f5b7e83dfbb5d169372";
|
||||
sha256 = "sha256-/37RJTjo+FJa1Flt59LrQbaJIcBid/z+Hy1xfhYGXNA=";
|
||||
};
|
||||
|
||||
buildInputs = [ ];
|
||||
|
||||
Reference in New Issue
Block a user