To simplify my configurations, I ever wonder to write all configuration keys into one file per device type, to reach all parameters immediately instead checking into splitted configuration.
So here is my node script. It merges all yaml files placed into ‘configuration’ subdirectory without duplicate keys and then place the result into configuration.yaml file.
Please, check before use it, for my configuration it works. Run with sudo npm compile.js
after npm install recursive-readdir
here it is:
var recursive = require("recursive-readdir")
var fs = require('fs')
var obj = {}
var current_key = ''
var obj_string = ''
recursive("configuration", function (err, files) {
// `files` is an array of absolute file paths
files.forEach((file) => {
console.log('Reading ' + file)
fs
.readFileSync(file).toString().split('\n')
.forEach(
(line) => {
line = line.replace("\r", "").replace("\t", " ")
let test_0 = line.match(/^\s*#.*/)
if (!test_0 && line.trim() !== '') {
// check no spaces
let test_1 = line.match(/^(\S.+)/)
if (test_1) {
current_key = test_1[0].replace(':','').trim()
console.log('Feeding "' + current_key + '"')
if (typeof obj[current_key] === 'undefined') {
obj[current_key] = []
}
}
if ((line.trim() === 'customize_glob:' || line.trim() === 'customize:')) {
current_key = line.trim().replace(':','').trim()
console.log('Feeding "' + current_key + '"')
if (typeof obj['homeassistant'][current_key] === 'undefined') {
obj['homeassistant'][current_key] = []
}
}
if (!test_1 && line.trim() !== 'customize_glob:' && line.trim() !== 'customize:') {
if (current_key === 'customize_glob' || current_key === 'customize') {
obj['homeassistant'][current_key].push(line)
} else {
obj[current_key].push(line)
}
}
} else {
console.log('Skipped line', line)
}
}
)
})
//console.log(obj)
console.log('Writing to configuration.yaml')
for (let key in obj)
{
console.log('"' + key + ':"')
obj_string+= key + ':\n'
for (let subkey in obj[key]) {
if (typeof obj[key][subkey] !== 'string') {
console.log('"' + ' ' + subkey + ':' + '"')
obj_string+= ' ' + subkey + ':\n'
for (let subkey2 in obj[key][subkey]) {
console.log('"' + obj[key][subkey][subkey2] + '"')
obj_string+= obj[key][subkey][subkey2] + '\n'
}
} else {
console.log('"' + obj[key][subkey])
obj_string+= obj[key][subkey] + '\n'
}
}
}
fs.truncate("./configuration.yaml", 0, function() {
fs.writeFile("./configuration.yaml", obj_string, function (err) {
if (err) {
return console.log("Error writing file: " + err);
} else {
return console.log('DONE!')
}
})
})
})
My .homeassistant directory structure is like this:
.homeassistant
- compile.js
/configuration
- automation.yaml
- trackers.yaml
- homeassistant.yaml
- windows.yaml
- etc...
configuration/homeassistant.yaml
contains all non-device related keys
group:
#default_view:
main:
name: main
view: yes
entities:
- updater.updater
- input_select.presenza
- group.covers
- group.switches
- group.livingcolors
- group.system
- group.camera_soggiorno
- group.camera_garage
- sensor.yr_symbol
- sensor.temperatura_esterna
- sensor.umidita_esterna
- device_tracker.motoxdavide
- group.zwave
security_automations:
name: Automazione Sicurezza
icon: mdi:robot
control: hidden
entities:
- input_select.presenza
- automation.attiva_sorveglianza_non_a_casa
- automation.disattiva_sorveglianza_non_a_casa
- automation.attiva_sorveglianza_notturna_automatica
- automation.disattiva_sorveglianza_notturna_automatica
homeassistant:
# Name of the location where Home Assistant is running
name: Home
# Location required to calculate the time the sun rises and sets
latitude: xx
longitude: xx
elevation: 9
# C for Celsius, F for Fahrenheit
#temperature_unit: C
# Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
time_zone: Europe/Rome
unit_system: metric
whitelist_external_dirs:
- /tmp
- /home/pi/FTP
customize_glob:
"*media_player*":
hidden: true
input_select:
presenza:
name: Presenza
options:
- A Casa
- Non a Casa
- Guardia
initial: A Casa
icon: mdi:incognito
zwave:
usb_path: /dev/ttyUSB0
# config_path: /srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/libopenzwave-0.3.1-py3.4-linux-armv7l.egg/config
device_config:
cover.fibaro_system_fgrm222_roller_shutter_controller_2_level:
invert_openclose_buttons: true
cover.fibaro_system_fgrm222_roller_shutter_controller_2_level_2:
invert_openclose_buttons: true
# ignored: false
# polling_intensity: 60
telegram_bot:
platform: webhooks
api_key: xxxx
allowed_chat_ids:
- xxxxx
notify:
name: telegram
platform: telegram
chat_id: xxxx
mqtt:
broker: 127.0.0.1
port: 1883
client_id: home-assistant-1
username: pi
password: xxxxx
# View all events in a logbook
logbook:
# Allows you to issue voice commands from the frontend
conversation:
# Discover some devices automatically
discovery:
# Enables the frontend
frontend:
# Enables support for tracking state changes over time.
history:
include:
domains:
- sensor
# - switch
# Checks for available updates
updater:
# Track the sun
sun:
elevation: 9
# Show links to resources in log and frontend
#introduction:
# Config panel
config:
http:
base_url: xxxx
api_password: xxxxx
ssl_certificate: /etc/letsencrypt/live/xxxx/fullchain.pem
ssl_key: /etc/letsencrypt/live/xxxx/privkey.pem
# host_name: xxxx
logger:
default: error
device_tracker:
- platform: fritz
host: 192.168.1.1
username: xxxx
password: xxx
track_new_devices: yes
interval_seconds: 300
consider_home: 0:10:00
- platform: nmap_tracker
hosts: 192.168.1.1/24
home_interval: 10
interval_seconds: 60
# exclude:
# - 192.168.1.1
# - 192.168.1.2
# - 192.168.1.4
alarm_control_panel:
platform: manual
code: xxxx
disarm_after_trigger: false
and, for example, my smart_socket.yaml
group:
asciugatrice:
name: Asciugatrice
icon: mdi:washing-machine
control: hidden
entities:
- switch.neo_coolcam_power_plug_12a_switch
- zwave.neo_coolcam_power_plug_12a
- sensor.neo_coolcam_power_plug_12a_voltage
- sensor.neo_coolcam_power_plug_12a_current
- sensor.neo_coolcam_power_plug_12a_power
- sensor.neo_coolcam_power_plug_12a_energy
- automation.avviso_asciugatrice_finita
smart_socket:
name: Smart Socket
icon: mdi:power-plug
control: hidden
entities:
- switch.neo_coolcam_power_plug_12a_switch_2
- zwave.neo_coolcam_power_plug_12a_2
- sensor.neo_coolcam_power_plug_12a_voltage_2
- sensor.neo_coolcam_power_plug_12a_current_2
- sensor.neo_coolcam_power_plug_12a_energy_2
homeassistant:
customize_glob:
"sensor.neo_coolcam_power_plug_12a_interval*":
hidden: true
"sensor.neo_coolcam_power_plug_12a_exporting*":
hidden: true
"sensor.neo_coolcam_power_plug_12a_alarm_type*":
hidden: true
"sensor.neo_coolcam_power_plug_12a_previous_reading*":
hidden: true
"sensor.neo_coolcam_power_plug_12a_sourcenodeid*":
hidden: true
"sensor.neo_coolcam_power_plug_12a_alarm_level*":
hidden: true
"switch.neo_coolcam_power_plug_12a_switch*":
icon: mdi:power-plug
friendly_name: Presa
hidden: false
"sensor.neo_coolcam_power_plug_12a_voltage*":
icon: mdi:speedometer
friendly_name: Tensione
hidden: false
"sensor.neo_coolcam_power_plug_12a_current*":
icon: mdi:trending-up
friendly_name: Corrente
hidden: false
"sensor.neo_coolcam_power_plug_12a_energy*":
icon: mdi:flash
friendly_name: Consumo
hidden: false
"sensor.neo_coolcam_power_plug_12a_power*":
icon: mdi:flash
friendly_name: Potenza
hidden: false
binary_sensor:
- platform: template
sensors:
asciugatrice_accesa:
friendly_name: Asciugatrice Accesa
entity_id: sensor.neo_coolcam_power_plug_12a_current
value_template: '{{ states.sensor.neo_coolcam_power_plug_12a_current.state | float > 0 }}'
As you can see the script permit to redeclare config keys many times… it merges values into one key at output. Hope this can helps someone.
The script also replaces tabs with double spaces and ignores commented rows.