8 Commits

Author SHA1 Message Date
5aaad54de3 Merge branch 'master' of ssh://gitea.communiquons.org:52001/pierre/SolarEnergy
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-10-19 09:25:48 +02:00
b3edfb05d9 Update Rust crate anyhow to v1.0.90
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-19 00:29:11 +00:00
45029f24cc Can use cURL to request fronius production 2024-10-18 21:18:00 +02:00
ec594c0e4d Fix typo
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-18 20:53:50 +02:00
fdfbdf093f Create production installation guide
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-18 20:41:08 +02:00
c789056ccf Improve env var name
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-10-18 20:05:40 +02:00
f5f783698f Add support for environment files
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-10-18 19:57:06 +02:00
823783f307 Update ESP-IDF to version 5.3.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-10-18 19:40:27 +02:00
7 changed files with 135 additions and 10 deletions

View File

@@ -56,7 +56,7 @@ steps:
- ls -lah target/release/central_backend - ls -lah target/release/central_backend
- name: esp32_compile - name: esp32_compile
image: espressif/idf:v5.2.2 # FIXME : upgrade to 5.3.1 image: espressif/idf:v5.3.1
commands: commands:
- cd esp32_device - cd esp32_device
- /opt/esp/entrypoint.sh idf.py build - /opt/esp/entrypoint.sh idf.py build

View File

@@ -492,9 +492,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.89" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
[[package]] [[package]]
name = "asn1" name = "asn1"
@@ -670,6 +670,7 @@ dependencies = [
"bincode", "bincode",
"chrono", "chrono",
"clap", "clap",
"dotenvy",
"env_logger", "env_logger",
"foreign-types-shared", "foreign-types-shared",
"fs4", "fs4",
@@ -997,6 +998,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
version = "1.0.0" version = "1.0.0"

View File

@@ -7,6 +7,7 @@ edition = "2021"
log = "0.4.22" log = "0.4.22"
env_logger = "0.11.5" env_logger = "0.11.5"
lazy_static = "1.5.0" lazy_static = "1.5.0"
dotenvy = "0.15.7"
clap = { version = "4.5.20", features = ["derive", "env"] } clap = { version = "4.5.20", features = ["derive", "env"] }
anyhow = "1.0.89" anyhow = "1.0.89"
thiserror = "1.0.64" thiserror = "1.0.64"

View File

@@ -38,9 +38,13 @@ pub enum ConsumptionBackend {
/// Fronius inverter consumption /// Fronius inverter consumption
Fronius { Fronius {
/// The origin of the domain where the webserver of the Fronius Symo can be reacher /// The origin of the domain where the webserver of the Fronius Symo can be reached
#[clap(short, long, env)]
fronius_orig: String,
/// Use cURL instead of reqwest to perform request
#[clap(short, long)] #[clap(short, long)]
origin: String, curl: bool,
}, },
} }
@@ -48,6 +52,10 @@ pub enum ConsumptionBackend {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct AppConfig { pub struct AppConfig {
/// Read arguments from env file
#[clap(short, long, env)]
pub config: Option<String>,
/// Proxy IP, might end with a star "*" /// Proxy IP, might end with a star "*"
#[clap(short, long, env)] #[clap(short, long, env)]
pub proxy_ip: Option<String>, pub proxy_ip: Option<String>,
@@ -114,6 +122,21 @@ lazy_static::lazy_static! {
} }
impl AppConfig { impl AppConfig {
/// Parse environment variables from file, if requedst
pub fn parse_env_file() -> anyhow::Result<()> {
if let Some(c) = Self::parse().config {
log::info!("Load additional environment variables from {c}");
let conf_file = Path::new(&c);
if !conf_file.is_file() {
panic!("Specified configuration is not a file!");
}
dotenvy::from_path(conf_file)?;
}
Ok(())
}
/// Get parsed command line arguments /// Get parsed command line arguments
pub fn get() -> &'static AppConfig { pub fn get() -> &'static AppConfig {
&ARGS &ARGS

View File

@@ -9,6 +9,8 @@ pub enum ConsumptionError {
NonExistentFile, NonExistentFile,
#[error("The file that should contain the consumption has an invalid content!")] #[error("The file that should contain the consumption has an invalid content!")]
FileInvalidContent(#[source] ParseIntError), FileInvalidContent(#[source] ParseIntError),
#[error("Failed to execute cURL request!")]
CurlReqFailed,
} }
pub type EnergyConsumption = i32; pub type EnergyConsumption = i32;
@@ -63,9 +65,21 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> {
.map_err(ConsumptionError::FileInvalidContent)?) .map_err(ConsumptionError::FileInvalidContent)?)
} }
ConsumptionBackend::Fronius { origin } => { ConsumptionBackend::Fronius { fronius_orig, curl } => {
let url = format!("{origin}/solar_api/v1/GetPowerFlowRealtimeData.fcgi"); let url = format!("{fronius_orig}/solar_api/v1/GetPowerFlowRealtimeData.fcgi");
let response = reqwest::get(url).await?.json::<FroniusResponse>().await?;
let response = match curl {
false => reqwest::get(url).await?.json::<FroniusResponse>().await?,
true => {
let res = std::process::Command::new("curl").arg(url).output()?;
if !res.status.success() {
return Err(ConsumptionError::CurlReqFailed.into());
}
serde_json::from_slice::<FroniusResponse>(&res.stdout)?
}
};
Ok(response.body.data.site.grid_production as i32) Ok(response.body.data.site.grid_production as i32)
} }

View File

@@ -9,6 +9,9 @@ use tokio_schedule::{every, Job};
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
// Load additional config from file, if requested
AppConfig::parse_env_file().expect("Failed to parse environment file!");
// Initialize OpenSSL // Initialize OpenSSL
openssl_sys::init(); openssl_sys::init();

View File

@@ -45,4 +45,81 @@ The OTA update is then located in `build/main.bin`
* DHCP configured on the network * DHCP configured on the network
## Configure server ## Configure server
TODO
### Create a user dedicated to the central
```bash
sudo adduser --disabled-login central
```
### Install binary
You can use `scp` to copy the binary to the target server:
```bash
scp central_backend/target/release/central_backend pierre@central:/home/pierre
```
Then the executable must be installed system-wide:
```bash
sudo mv central_backend /usr/local/bin/
```
### Create configuration file
Create a configuration file in `/home/central/config.yaml`:
```bash
sudo touch /home/central/config.yaml
sudo chown central:central /home/central/config.yaml
sudo chmod 400 /home/central/config.yaml
sudo nano /home/central/config.yaml
```
Sample configuration:
```conf
SECRET=RANDOM_VALUE
COOKIE_SECURE=true
LISTEN_ADDRESS=0.0.0.0:443
ADMIN_USERNAME=admin
ADMIN_PASSWORD=FIXME
HOSTNAME=central.local
STORAGE=/home/central/storage
FRONIUS_ORIG=http://10.0.0.10
```
### Test configuration
Run the following command to check if the configuration is working:
```bash
sudo -u central central_backend -c /home/central/config.yaml fronius -c
```
### Create systemd unit file
Once you confirmed the configuration is working, you can configure a system service, in `/etc/systemd/system/central.service`:
```conf
[Unit]
Description=Central backend server
After=syslog.target
After=network.target
[Service]
RestartSec=2s
Type=simple
User=central
Group=central
WorkingDirectory=/home/central
ExecStart=/usr/local/bin/central_backend -c /home/central/config.yaml fronius -c
Restart=always
Environment=USER=central
HOME=/home/central
[Install]
WantedBy=multi-user.target
```
Enable & start service:
```bash
sudo systemctl enable central
sudo systemctl start central
```