initial for multiple devices, introduce real configuration
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
include:
|
||||
- project: dockerized/commons
|
||||
ref: master
|
||||
file: gitlab-ci-template.yml
|
||||
|
||||
@@ -5,14 +5,14 @@ steps:
|
||||
repo: gitea.hottis.de/wn/pv-controller
|
||||
registry:
|
||||
from_secret: container_registry
|
||||
tags: latest,${CI_COMMIT_SHA},${CI_COMMIT_TAG}
|
||||
tags: latest,${CI_COMMIT_TAG}
|
||||
username:
|
||||
from_secret: container_registry_username
|
||||
password:
|
||||
from_secret: container_registry_password
|
||||
dockerfile: Dockerfile
|
||||
when:
|
||||
- event: [push, tag]
|
||||
- event: tag
|
||||
|
||||
deploy:
|
||||
image: portainer/kubectl-shell:latest
|
||||
|
||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Wolfgang Hottgenroth
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
134
config/config.yaml
Normal file
134
config/config.yaml
Normal file
@@ -0,0 +1,134 @@
|
||||
mqtt:
|
||||
broker: ${MQTT__BROKER}
|
||||
port: ${MQTT__PORT}
|
||||
|
||||
modbus:
|
||||
gateway: ${MODBUS__GATEWAY}
|
||||
|
||||
|
||||
# REGISTERS = [
|
||||
# { "slave":2, "addr":0x0048, "type":"input", "attr": "importEnergyActive", "name":"Import active energy", "unit":"kWh", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x004c, "type":"input", "attr": "importEnergyReactive", "name":"Import reactive energy", "unit":"kVAh", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x004a, "type":"input", "attr": "exportEnergyActive", "name":"Export active energy", "unit":"kWh", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x004e, "type":"input", "attr": "exportEnergyReactive", "name":"Export reactive energy", "unit":"kVAh", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0012, "type":"input", "attr": "powerApparent", "name":"Apparent Power", "unit":"W", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x000c, "type":"input", "attr": "powerActive", "name":"Active Power", "unit":"W", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0018, "type":"input", "attr": "powerReactive", "name":"Reactive Power", "unit":"W", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0058, "type":"input", "attr": "powerDemandPositive", "name":"PositivePowerDemand", "unit":"W", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x005c, "type":"input", "attr": "powerDemandReverse", "name":"ReversePowerDemand", "unit":"W", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x001e, "type":"input", "attr": "factor", "name":"Factor", "unit":"-", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0024, "type":"input", "attr": "angle", "name":"Angle", "unit":"degree", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0000, "type":"input", "attr": "voltage", "name":"Voltage", "unit":"V", "adaptor": floatAdaptor },
|
||||
# { "slave":2, "addr":0x0006, "type":"input", "attr": "current", "name":"Current", "unit":"A", "adaptor": floatAdaptor },
|
||||
# { "slave":1, "addr":0x0001, "type":"holding", "attr": "state", "name":"State", "unit":"-", "adaptor": onOffAdaptor },
|
||||
# ]
|
||||
|
||||
output:
|
||||
- name: pv_meter
|
||||
publish_topic: IoT/PV/Values
|
||||
publish_period: 15
|
||||
slave_id: 2
|
||||
registers:
|
||||
- address: 0x0048
|
||||
attribute: importEnergyActive
|
||||
name: Import active energy
|
||||
unit: kWh
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x004c
|
||||
attribute: importEnergyReactive
|
||||
name: Import reactive energy
|
||||
unit: kVAh
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x004a
|
||||
attribute: exportEnergyActive
|
||||
name: Export active energy
|
||||
unit: kWh
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x004e
|
||||
attribute: exportEnergyReactive
|
||||
name: Export reactive energy
|
||||
unit: kVAh
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0012
|
||||
attribute: powerApparent
|
||||
name: Apparent Power
|
||||
unit: W
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x000c
|
||||
attribute: powerActive
|
||||
name: Active Power
|
||||
unit: W
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0018
|
||||
attribute: powerReactive
|
||||
name: Reactive Power
|
||||
unit: W
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0058
|
||||
attribute: powerDemandPositive
|
||||
name: PositivePowerDemand
|
||||
unit: W
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x005c
|
||||
attribute: powerDemandReverse
|
||||
name: ReversePowerDemand
|
||||
unit: W
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x001e
|
||||
attribute: factor
|
||||
name: Factor
|
||||
unit: "-"
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0024
|
||||
attribute: angle
|
||||
name: Angle
|
||||
unit: degree
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0000
|
||||
attribute: voltage
|
||||
name: Voltage
|
||||
unit: V
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- address: 0x0006
|
||||
attribute: current
|
||||
name: Current
|
||||
unit: A
|
||||
register_type: input
|
||||
data_type: float
|
||||
adaptor: floatAdaptor
|
||||
- name: pv_control
|
||||
publish_topic: IoT/PV/Control
|
||||
publish_period: 15
|
||||
slave_id: 1
|
||||
registers:
|
||||
- address: 0x0001
|
||||
attribute: state
|
||||
name: State
|
||||
unit: "-"
|
||||
register_type: holding
|
||||
data_type: int
|
||||
adaptor: onOffAdaptor
|
||||
12
requirements.txt
Normal file
12
requirements.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# Configuration and validation
|
||||
pydantic>=2.0.0
|
||||
pyyaml>=6.0
|
||||
|
||||
# Logging
|
||||
loguru>=0.7.0
|
||||
|
||||
# MQTT client
|
||||
paho-mqtt>=1.6.0
|
||||
|
||||
# Modbus communication
|
||||
pymodbus>=3.0.0
|
||||
@@ -1,67 +0,0 @@
|
||||
with
|
||||
first_day_in_year as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('year', time) and now()
|
||||
),
|
||||
first_value_in_year as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_year) and (select day from first_day_in_year) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
first_day_in_month as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('month', now()) and now()
|
||||
),
|
||||
first_value_in_month as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_month) and (select day from first_day_in_month) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
first_value_in_day as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where time >= date_trunc('day', now())
|
||||
group by interval
|
||||
),
|
||||
last_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
last(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('day', now()) and date_trunc('day', now()) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
)
|
||||
select
|
||||
extract(year from (select day from first_day_in_year))::text as period_value,
|
||||
'Year' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_year))::numeric, 2) as yield
|
||||
union
|
||||
select
|
||||
to_char((select day from first_day_in_month), 'Month') as period_value,
|
||||
'Month' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_month))::numeric, 2) as yield
|
||||
union
|
||||
select
|
||||
now()::date::text as period_value,
|
||||
'Day' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_day))::numeric, 2) as yield;
|
||||
@@ -1,88 +0,0 @@
|
||||
create table pv_power_measurement_t (
|
||||
time timestamp without time zone not null,
|
||||
deviceid text,
|
||||
status text,
|
||||
state integer,
|
||||
importEnergyActive double precision,
|
||||
importEnergyReactive double precision,
|
||||
exportEnergyActive double precision,
|
||||
exportEnergyReactive double precision,
|
||||
powerApparent double precision,
|
||||
powerActive double precision,
|
||||
powerReactive double precision,
|
||||
powerDemandPositive double precision,
|
||||
powerDemandReverse double precision,
|
||||
powerDemand double precision,
|
||||
factor double precision,
|
||||
angle double precision,
|
||||
voltage double precision,
|
||||
current double precision
|
||||
);
|
||||
|
||||
select create_hypertable('pv_power_measurement_t', 'time');
|
||||
|
||||
grant insert on pv_power_measurement_t to nodered;
|
||||
grant select on pv_power_measurement_t to grafana;
|
||||
|
||||
create view pv_stats_v as
|
||||
select time, importEnergyActive, importEnergyReactive, exportEnergyActive, exportEnergyReactive,
|
||||
powerApparent, powerActive, powerReactive, powerDemandPositive, powerDemandReverse, powerDemand,
|
||||
factor, angle, voltage, current
|
||||
from pv_power_measurement_t
|
||||
order by time;
|
||||
|
||||
|
||||
create table pv_stats_t (
|
||||
id serial not null primary key,
|
||||
"date" date not null,
|
||||
dateType varchar(5) not null,
|
||||
first numeric(10,2) not null default 0,
|
||||
total numeric(10,2) not null default 0
|
||||
);
|
||||
alter table pv_stats_t add constraint ddT_uk unique ("date", dateType);
|
||||
|
||||
grant insert, select, update on pv_stats_t to nodered;
|
||||
grant select, update on pv_stats_t_id_seq to nodered;
|
||||
|
||||
create or replace function pv_stats_func ()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
declare
|
||||
v_stat_id pv_stats_t.id%TYPE;
|
||||
v_dateTypes varchar[] := array['day', 'month', 'year'];
|
||||
v_dateType varchar;
|
||||
begin
|
||||
foreach v_dateType in array v_dateTypes
|
||||
loop
|
||||
select id
|
||||
from pv_stats_t
|
||||
into v_stat_id
|
||||
where "date" = date_trunc(v_dateType, NEW.time::date) and
|
||||
dateType = v_dateType;
|
||||
if not found then
|
||||
insert into pv_stats_t ("date", dateType, first)
|
||||
values (date_trunc(v_dateType, NEW.time::date), v_dateType, NEW.exportEnergyActive);
|
||||
else
|
||||
update pv_stats_t
|
||||
set total = NEW.exportEnergyActive - first
|
||||
where id = v_stat_id;
|
||||
end if;
|
||||
|
||||
end loop;
|
||||
|
||||
return NEW;
|
||||
end;
|
||||
$$
|
||||
|
||||
create trigger pv_stats_trig
|
||||
after insert on pv_power_measurement_t
|
||||
for each row
|
||||
execute function pv_stats_func();
|
||||
|
||||
|
||||
|
||||
insert into pv_stats_t("date", dateType, first, total) values (date_trunc('month', now()), 'month', 0.01, 0)
|
||||
on conflict on constraint ddT_uk do update set total = 3.26 - excluded.first;
|
||||
|
||||
;
|
||||
@@ -1,160 +0,0 @@
|
||||
-- current year's gain
|
||||
with
|
||||
first_day_in_year as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('year', time) and now()
|
||||
),
|
||||
first_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_year) and (select day from first_day_in_year) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
last_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
last(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('day', now()) and date_trunc('day', now()) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
)
|
||||
select
|
||||
extract(year from (select day from first_day_in_year))::text as period_value,
|
||||
'Year' as period_name,
|
||||
(select energy from last_value) - (select energy from first_value) as yield;
|
||||
|
||||
|
||||
|
||||
-- current month's gain
|
||||
with
|
||||
first_day_in_month as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('month', now()) and now()
|
||||
),
|
||||
first_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_month) and (select day from first_day_in_month) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
last_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
last(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('day', now()) and date_trunc('day', now()) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
)
|
||||
select
|
||||
(select day from first_day_in_month) as v1,
|
||||
(select energy from first_value) as v2,
|
||||
(select energy from last_value) as v3,
|
||||
to_char((select day from first_day_in_month), 'Month') as period_value,
|
||||
'Month' as period_name,
|
||||
(select energy from last_value) - (select energy from first_value) as yield;
|
||||
|
||||
|
||||
|
||||
-- current day's gain
|
||||
with
|
||||
values as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as first_value,
|
||||
last(exportenergyactive, time) as last_value
|
||||
from pv_power_measurement_t
|
||||
where time >= date_trunc('day', now())
|
||||
group by interval
|
||||
)
|
||||
select
|
||||
(select interval from values)::date::text as period_value,
|
||||
'Day' as period_name,
|
||||
(select last_value from values) - (select first_value from values) as yield;
|
||||
|
||||
|
||||
-- all in one
|
||||
with
|
||||
first_day_in_year as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('year', time) and now()
|
||||
),
|
||||
first_value_in_year as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_year) and (select day from first_day_in_year) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
first_day_in_month as (
|
||||
select
|
||||
date_trunc('day', min(time)) as day
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('month', time) and now()
|
||||
),
|
||||
first_value_in_month as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between (select day from first_day_in_month) and (select day from first_day_in_month) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
),
|
||||
first_value_in_day as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
first(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where time >= date_trunc('day', now())
|
||||
group by interval
|
||||
),
|
||||
last_value as (
|
||||
select
|
||||
time_bucket('1 day', time) as interval,
|
||||
last(exportenergyactive, time) as energy
|
||||
from pv_power_measurement_t
|
||||
where
|
||||
time between date_trunc('day', now()) and date_trunc('day', now()) + interval '1 day' and
|
||||
status = 'Ok'
|
||||
group by interval
|
||||
)
|
||||
select
|
||||
extract(year from (select day from first_day_in_year))::text as period_value,
|
||||
'Year' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_year))::numeric, 2) as yield
|
||||
union
|
||||
select
|
||||
to_char((select day from first_day_in_month), 'Month') as period_value,
|
||||
'Month' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_month))::numeric, 2) as yield
|
||||
union
|
||||
select
|
||||
now()::date::text as period_value,
|
||||
'Day' as period_name,
|
||||
round(((select energy from last_value) - (select energy from first_value_in_day))::numeric, 2) as yield;
|
||||
@@ -1,20 +0,0 @@
|
||||
select time_bucket('1 day', time) as interval,
|
||||
round((last(exportenergyactive, time) - first(exportenergyactive, time))::numeric, 2) as energy
|
||||
from pv_power_measurement_t
|
||||
where time between date_trunc('month', now()) and date_trunc('month', now()) + interval '1 month'
|
||||
group by interval
|
||||
order by interval;
|
||||
|
||||
|
||||
|
||||
-- daily stats of current month
|
||||
|
||||
|
||||
|
||||
|
||||
select time_bucket('1 day', time) as interval,
|
||||
round((last(exportenergyactive, time) - first(exportenergyactive, time))::numeric, 2) as energy
|
||||
from pv_power_measurement_t
|
||||
where time between date_trunc('month', now()) and date_trunc('month', now()) + interval '1 month'
|
||||
group by interval
|
||||
order by interval;
|
||||
@@ -1,33 +1,76 @@
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
import yaml
|
||||
from loguru import logger
|
||||
|
||||
class Config:
|
||||
OPTIONS = {
|
||||
'mqtt': [ 'login',
|
||||
'password',
|
||||
'ca',
|
||||
'cert',
|
||||
'key',
|
||||
'broker',
|
||||
'port',
|
||||
'meterPublishTopic',
|
||||
'meterPublishPeriod',
|
||||
'relaisSubscribeTopic' ],
|
||||
'modbus': [ 'gateway' ]
|
||||
}
|
||||
|
||||
class RegisterConfig(BaseModel):
|
||||
"""Modbus Register Configuration"""
|
||||
address: int
|
||||
attribute: str
|
||||
name: str
|
||||
unit: str
|
||||
register_type: str
|
||||
data_type: str
|
||||
adaptor: str
|
||||
|
||||
|
||||
class OutputConfig(BaseModel):
|
||||
"""Output Configuration for Modbus Devices"""
|
||||
name: str
|
||||
publish_topic: str
|
||||
publish_period: int
|
||||
slave_id: int
|
||||
registers: List[RegisterConfig]
|
||||
|
||||
|
||||
class MqttConfig(BaseModel):
|
||||
"""MQTT Configuration"""
|
||||
broker: str
|
||||
port: int
|
||||
|
||||
|
||||
class ModbusConfig(BaseModel):
|
||||
"""Modbus Configuration"""
|
||||
gateway: str
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
"""Main Configuration"""
|
||||
mqtt: MqttConfig
|
||||
modbus: ModbusConfig
|
||||
output: List[OutputConfig]
|
||||
|
||||
@classmethod
|
||||
def load_from_file(cls, config_path: Optional[str] = None) -> 'Config':
|
||||
"""
|
||||
Load configuration from YAML file with environment variable substitution.
|
||||
|
||||
Args:
|
||||
config_path: Path to config file. If None, uses CFG_FILE environment variable.
|
||||
|
||||
Returns:
|
||||
Config instance
|
||||
"""
|
||||
if config_path is None:
|
||||
config_path = os.getenv('CFG_FILE')
|
||||
if config_path is None:
|
||||
raise ValueError("Config path not provided and CFG_FILE environment variable not set")
|
||||
|
||||
config_file = Path(config_path)
|
||||
if not config_file.exists():
|
||||
raise FileNotFoundError(f"Configuration file not found: {config_path}")
|
||||
|
||||
# Read YAML file
|
||||
with open(config_file, 'r', encoding='utf-8') as f:
|
||||
yaml_content = f.read()
|
||||
|
||||
# Parse YAML
|
||||
config_dict = yaml.safe_load(yaml_content)
|
||||
|
||||
logger.info(f"Configuration loaded from: {config_path}")
|
||||
return cls(**config_dict)
|
||||
|
||||
def __init__(self):
|
||||
self.values = {}
|
||||
for section, keys in Config.OPTIONS.items():
|
||||
self.values[section] = {}
|
||||
for key in keys:
|
||||
varname = f"{section}__{key}".upper()
|
||||
try:
|
||||
self.values[section][key] = os.environ[varname]
|
||||
logger.info(f"Config: {section} {key} -> {self.values[section][key]}")
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def __getitem__(self, section):
|
||||
return self.values[section]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user