Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
066e9f7bf8 | |||
e923ecb9d8 | |||
2f5bb538b2 | |||
41cc9e0622 | |||
d4ff664f74 | |||
277b159200 | |||
ce7a79d1de | |||
929985c64a | |||
473832f58a | |||
9326b66007 | |||
f26e66d687 | |||
b14049b3f6 | |||
228b366320 | |||
e9b09cd709 | |||
cacd740bd9 | |||
98db89ce03 | |||
fc4c1df09a | |||
19e2ea003b |
36 changed files with 1434 additions and 1196 deletions
.sqlx
query-2b34934e10005378c331f489751dcc4dc5cc79a52299cb74018e36212809288a.jsonquery-2b5ac2227f48be1483f4097da6f890be8091daa97b0af548b6ebf60cdc03dfba.jsonquery-493ad91be9ce523e9d0f03f5caa9b3255a5426d54901f4f3aa96ad152b05ffd0.jsonquery-4a99db9678cf8d1bdb082c4a13a1f5cdd699bfe7600389e37ca980b6fad12bb5.jsonquery-5056b625241d9cbe63d98e00ac39085677c09be8be903804120c2d52579afdbb.jsonquery-5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465.jsonquery-9224ad423f2c86f3d95f2b0b7d99a27f690020f89958dfc8dd6044a31afdb31d.jsonquery-adbce2c94ac0b54d0826b28f99fe63322d3bb1579e52d0f053307e24bd039ef9.jsonquery-d57c388bf6c26fe6cadad35d0f254ca2ef93958f9975c585c6de3c437782995d.jsonquery-f85f0a96bb98d20e47677b0679d552812362c3141738b60bc63d673a7f552506.json
Cargo.lockCargo.tomlMakefilemigrations
src
12
.sqlx/query-2b34934e10005378c331f489751dcc4dc5cc79a52299cb74018e36212809288a.json
generated
Normal file
12
.sqlx/query-2b34934e10005378c331f489751dcc4dc5cc79a52299cb74018e36212809288a.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "UPDATE macros SET name = ? WHERE id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "2b34934e10005378c331f489751dcc4dc5cc79a52299cb74018e36212809288a"
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT * FROM relays WHERE controller_id = ?",
|
"query": "SELECT * FROM v_relays WHERE id = ?",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2"
|
"hash": "2b5ac2227f48be1483f4097da6f890be8091daa97b0af548b6ebf60cdc03dfba"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT relays.* FROM relays INNER JOIN junction_relay_schedule\n\t\t\tON junction_relay_schedule.relay_id = relays.id\n\t\t\tWHERE junction_relay_schedule.schedule_id = ?\n\t\t\tORDER BY junction_relay_schedule.weekday",
|
"query": "SELECT v_relays.* FROM v_relays INNER JOIN junction_tag ON junction_tag.relay_id = v_relays.id WHERE junction_tag.tag_id = ?",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "2551c285e3e223311cff8e32022d8b11e95d56b2f166326301a0b6722fc1fd44"
|
"hash": "493ad91be9ce523e9d0f03f5caa9b3255a5426d54901f4f3aa96ad152b05ffd0"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT relay.* FROM relays AS relay INNER JOIN junction_tag ON junction_tag.relay_id = relay.id WHERE junction_tag.tag_id = ?",
|
"query": "SELECT * FROM v_relays WHERE v_relays.controller_id = ?",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f"
|
"hash": "4a99db9678cf8d1bdb082c4a13a1f5cdd699bfe7600389e37ca980b6fad12bb5"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT * FROM relays",
|
"query": "SELECT * FROM v_relays",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d"
|
"hash": "5056b625241d9cbe63d98e00ac39085677c09be8be903804120c2d52579afdbb"
|
||||||
}
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?) RETURNING *",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Int64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "number",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Int64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "controller_id",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Int64"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 3
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465"
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT * FROM relays WHERE controller_id = ? AND number = ?",
|
"query": "SELECT * FROM v_relays WHERE v_relays.controller_id = ? AND v_relays.number = ?",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153"
|
"hash": "9224ad423f2c86f3d95f2b0b7d99a27f690020f89958dfc8dd6044a31afdb31d"
|
||||||
}
|
}
|
44
.sqlx/query-adbce2c94ac0b54d0826b28f99fe63322d3bb1579e52d0f053307e24bd039ef9.json
generated
Normal file
44
.sqlx/query-adbce2c94ac0b54d0826b28f99fe63322d3bb1579e52d0f053307e24bd039ef9.json
generated
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT v_relays.* FROM v_relays INNER JOIN junction_relay_schedule\n\t\t\tON junction_relay_schedule.relay_id = v_relays.id\n\t\t\tWHERE junction_relay_schedule.schedule_id = ?\n\t\t\tORDER BY junction_relay_schedule.weekday",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "number",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_id",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "adbce2c94ac0b54d0826b28f99fe63322d3bb1579e52d0f053307e24bd039ef9"
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT * FROM relays WHERE id = ?",
|
"query": "SELECT * FROM v_relays WHERE v_relays.id = ?",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@
|
||||||
"name": "controller_id",
|
"name": "controller_id",
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controller_uid",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
@ -31,8 +36,9 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111"
|
"hash": "d57c388bf6c26fe6cadad35d0f254ca2ef93958f9975c585c6de3c437782995d"
|
||||||
}
|
}
|
12
.sqlx/query-f85f0a96bb98d20e47677b0679d552812362c3141738b60bc63d673a7f552506.json
generated
Normal file
12
.sqlx/query-f85f0a96bb98d20e47677b0679d552812362c3141738b60bc63d673a7f552506.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?)",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 3
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "f85f0a96bb98d20e47677b0679d552812362c3141738b60bc63d673a7f552506"
|
||||||
|
}
|
1897
Cargo.lock
generated
1897
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
16
Cargo.toml
16
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "emgauwa-common"
|
name = "emgauwa-common"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Tobias Reisinger <tobias@msrg.cc>"]
|
authors = ["Tobias Reisinger <tobias@msrg.cc>"]
|
||||||
|
|
||||||
|
@ -8,25 +8,21 @@ authors = ["Tobias Reisinger <tobias@msrg.cc>"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "0.13"
|
actix = "0.13"
|
||||||
actix-web = "4.4"
|
actix-web = "4.4"
|
||||||
actix-web-actors = "4.2"
|
|
||||||
|
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
serde_with = "3.8"
|
||||||
|
|
||||||
simple_logger = "4.2"
|
simple_logger = "5.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
config = "0.13"
|
config = "0.14"
|
||||||
|
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
|
||||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] }
|
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros"] }
|
||||||
libsqlite3-sys = { version = "*", features = ["bundled"] }
|
libsqlite3-sys = { version = "*", features = ["bundled"] }
|
||||||
uuid = "1.6"
|
uuid = { version = "1.8", features = ["v4"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|
||||||
rppal = "0.17"
|
|
||||||
rppal-pfd = "0.0.5"
|
|
||||||
rppal-mcp23s17 = "0.0.3"
|
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,3 +1,5 @@
|
||||||
|
export DATABASE_URL=sqlite://${PWD}/emgauwa-dev.sqlite
|
||||||
|
|
||||||
sqlx:
|
sqlx:
|
||||||
cargo sqlx database drop -y
|
cargo sqlx database drop -y
|
||||||
cargo sqlx database create
|
cargo sqlx database create
|
||||||
|
|
1
migrations/20240611000000_add_relays_view.down.sql
Normal file
1
migrations/20240611000000_add_relays_view.down.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DROP VIEW v_relays;
|
8
migrations/20240611000000_add_relays_view.up.sql
Normal file
8
migrations/20240611000000_add_relays_view.up.sql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE VIEW v_relays
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
relays.*,
|
||||||
|
controllers.uid AS controller_uid
|
||||||
|
FROM
|
||||||
|
relays
|
||||||
|
INNER JOIN controllers ON controllers.id = relays.controller_id;
|
|
@ -158,7 +158,7 @@ impl DbController {
|
||||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
DbRelay,
|
DbRelay,
|
||||||
"SELECT * FROM relays WHERE controller_id = ?",
|
"SELECT * FROM v_relays WHERE v_relays.controller_id = ?",
|
||||||
self.id
|
self.id
|
||||||
)
|
)
|
||||||
.fetch_all(conn.deref_mut())
|
.fetch_all(conn.deref_mut())
|
||||||
|
|
|
@ -5,11 +5,10 @@ use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::{DbRelay, DbSchedule};
|
use crate::db::{DbRelay, DbSchedule};
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::types::Weekday;
|
|
||||||
|
|
||||||
pub struct DbJunctionRelaySchedule {
|
pub struct DbJunctionRelaySchedule {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub weekday: Weekday,
|
pub weekday: i64,
|
||||||
pub relay_id: i64,
|
pub relay_id: i64,
|
||||||
pub schedule_id: i64,
|
pub schedule_id: i64,
|
||||||
}
|
}
|
||||||
|
@ -32,7 +31,7 @@ impl DbJunctionRelaySchedule {
|
||||||
pub async fn get_junction_by_relay_and_weekday(
|
pub async fn get_junction_by_relay_and_weekday(
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
relay: &DbRelay,
|
relay: &DbRelay,
|
||||||
weekday: Weekday,
|
weekday: i64,
|
||||||
) -> Result<Option<DbJunctionRelaySchedule>, DatabaseError> {
|
) -> Result<Option<DbJunctionRelaySchedule>, DatabaseError> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
DbJunctionRelaySchedule,
|
DbJunctionRelaySchedule,
|
||||||
|
@ -51,8 +50,8 @@ impl DbJunctionRelaySchedule {
|
||||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
DbRelay,
|
DbRelay,
|
||||||
r#"SELECT relays.* FROM relays INNER JOIN junction_relay_schedule
|
r#"SELECT v_relays.* FROM v_relays INNER JOIN junction_relay_schedule
|
||||||
ON junction_relay_schedule.relay_id = relays.id
|
ON junction_relay_schedule.relay_id = v_relays.id
|
||||||
WHERE junction_relay_schedule.schedule_id = ?
|
WHERE junction_relay_schedule.schedule_id = ?
|
||||||
ORDER BY junction_relay_schedule.weekday"#,
|
ORDER BY junction_relay_schedule.weekday"#,
|
||||||
schedule.id
|
schedule.id
|
||||||
|
@ -65,7 +64,7 @@ impl DbJunctionRelaySchedule {
|
||||||
pub async fn get_schedule(
|
pub async fn get_schedule(
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
relay: &DbRelay,
|
relay: &DbRelay,
|
||||||
weekday: Weekday,
|
weekday: i64,
|
||||||
) -> Result<Option<DbSchedule>, DatabaseError> {
|
) -> Result<Option<DbSchedule>, DatabaseError> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
DbSchedule,
|
DbSchedule,
|
||||||
|
@ -101,7 +100,7 @@ impl DbJunctionRelaySchedule {
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
relay: &DbRelay,
|
relay: &DbRelay,
|
||||||
schedule: &DbSchedule,
|
schedule: &DbSchedule,
|
||||||
weekday: Weekday,
|
weekday: i64,
|
||||||
) -> Result<DbJunctionRelaySchedule, DatabaseError> {
|
) -> Result<DbJunctionRelaySchedule, DatabaseError> {
|
||||||
match Self::get_junction_by_relay_and_weekday(conn, relay, weekday).await? {
|
match Self::get_junction_by_relay_and_weekday(conn, relay, weekday).await? {
|
||||||
None => sqlx::query_as!(
|
None => sqlx::query_as!(
|
||||||
|
@ -139,7 +138,7 @@ impl DbJunctionRelaySchedule {
|
||||||
schedules: Vec<&DbSchedule>,
|
schedules: Vec<&DbSchedule>,
|
||||||
) -> Result<(), DatabaseError> {
|
) -> Result<(), DatabaseError> {
|
||||||
for (weekday, schedule) in schedules.iter().enumerate() {
|
for (weekday, schedule) in schedules.iter().enumerate() {
|
||||||
Self::set_schedule(conn, relay, schedule, weekday as Weekday).await?;
|
Self::set_schedule(conn, relay, schedule, weekday as i64).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ impl DbMacro {
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
new_name: &str,
|
new_name: &str,
|
||||||
) -> Result<DbMacro, DatabaseError> {
|
) -> Result<DbMacro, DatabaseError> {
|
||||||
sqlx::query!("UPDATE relays SET name = ? WHERE id = ?", new_name, self.id,)
|
sqlx::query!("UPDATE macros SET name = ? WHERE id = ?", new_name, self.id,)
|
||||||
.execute(conn.deref_mut())
|
.execute(conn.deref_mut())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ pub use relays::DbRelay;
|
||||||
pub use schedules::{DbPeriods, DbSchedule};
|
pub use schedules::{DbPeriods, DbSchedule};
|
||||||
pub use tag::DbTag;
|
pub use tag::DbTag;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) use model_utils::Period;
|
||||||
|
|
||||||
use crate::errors::{DatabaseError, EmgauwaError};
|
use crate::errors::{DatabaseError, EmgauwaError};
|
||||||
|
|
||||||
static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations"
|
static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations"
|
||||||
|
@ -33,14 +36,14 @@ pub async fn run_migrations(pool: &Pool<Sqlite>) -> Result<(), EmgauwaError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(db: &str) -> Result<Pool<Sqlite>, EmgauwaError> {
|
pub async fn init(db: &str, pool_size: u32) -> Result<Pool<Sqlite>, EmgauwaError> {
|
||||||
let options = SqliteConnectOptions::from_str(db)?
|
let options = SqliteConnectOptions::from_str(db)?
|
||||||
.create_if_missing(true)
|
.create_if_missing(true)
|
||||||
.log_statements(log::LevelFilter::Trace);
|
.log_statements(log::LevelFilter::Trace);
|
||||||
|
|
||||||
let pool: Pool<Sqlite> = SqlitePoolOptions::new()
|
let pool: Pool<Sqlite> = SqlitePoolOptions::new()
|
||||||
.acquire_timeout(std::time::Duration::from_secs(1))
|
.acquire_timeout(std::time::Duration::from_secs(1))
|
||||||
.max_connections(5)
|
.max_connections(pool_size)
|
||||||
.connect_with(options)
|
.connect_with(options)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -51,13 +51,34 @@ impl Period {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_always_on(&self) -> bool {
|
||||||
|
self.start.eq(&self.end)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
||||||
self.start.eq(&self.end) || (self.start.le(now) && self.end.gt(now))
|
if self.is_always_on() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_after_now = self.start.gt(now);
|
||||||
|
// add check for end time being 00:00 because end being 00:00 would cause end_after_now to always be false
|
||||||
|
// this will handle end like 24:00 and end_after_now will be true
|
||||||
|
// same for start_before_end
|
||||||
|
let end_after_now = self.end.gt(now) || self.end.eq(&NaiveTime::MIN);
|
||||||
|
let start_before_end = self.start.lt(&self.end) || self.end.eq(&NaiveTime::MIN);
|
||||||
|
|
||||||
|
match (start_after_now, end_after_now, start_before_end) {
|
||||||
|
(false, false, true) => false, // both before now; start before end means "normal" period before now
|
||||||
|
(false, false, false) => true, // both before now; end before start means "inverse" period around now
|
||||||
|
(true, false, _) => false, // only start after now
|
||||||
|
(false, true, _) => true, // only end after now
|
||||||
|
(true, true, true) => false, // both after now but start first
|
||||||
|
(true, true, false) => true, // both after now but end first
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||||
if self.start.eq(&self.end) {
|
if self.is_always_on() {
|
||||||
// this period is always on
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,9 @@ use serde_derive::{Deserialize, Serialize};
|
||||||
use sqlx::pool::PoolConnection;
|
use sqlx::pool::PoolConnection;
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::{DbController, DbJunctionRelaySchedule, DbJunctionTag, DbSchedule, DbTag};
|
use crate::db::{DbController, DbJunctionTag, DbTag};
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::types::Weekday;
|
use crate::types::EmgauwaUid;
|
||||||
use crate::utils;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct DbRelay {
|
pub struct DbRelay {
|
||||||
|
@ -15,13 +14,15 @@ pub struct DbRelay {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub number: i64,
|
pub number: i64,
|
||||||
|
#[serde(rename = "controller_id")]
|
||||||
|
pub controller_uid: EmgauwaUid,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub controller_id: i64,
|
pub controller_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbRelay {
|
impl DbRelay {
|
||||||
pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbRelay>, DatabaseError> {
|
pub async fn get_all(conn: &mut PoolConnection<Sqlite>) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(DbRelay, "SELECT * FROM relays")
|
sqlx::query_as!(DbRelay, "SELECT * FROM v_relays")
|
||||||
.fetch_all(conn.deref_mut())
|
.fetch_all(conn.deref_mut())
|
||||||
.await
|
.await
|
||||||
.map_err(DatabaseError::from)
|
.map_err(DatabaseError::from)
|
||||||
|
@ -31,7 +32,7 @@ impl DbRelay {
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
id: i64,
|
id: i64,
|
||||||
) -> Result<Option<DbRelay>, DatabaseError> {
|
) -> Result<Option<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(DbRelay, "SELECT * FROM relays WHERE id = ?", id)
|
sqlx::query_as!(DbRelay, "SELECT * FROM v_relays WHERE v_relays.id = ?", id)
|
||||||
.fetch_optional(conn.deref_mut())
|
.fetch_optional(conn.deref_mut())
|
||||||
.await
|
.await
|
||||||
.map_err(DatabaseError::from)
|
.map_err(DatabaseError::from)
|
||||||
|
@ -44,7 +45,7 @@ impl DbRelay {
|
||||||
) -> Result<Option<DbRelay>, DatabaseError> {
|
) -> Result<Option<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
DbRelay,
|
DbRelay,
|
||||||
"SELECT * FROM relays WHERE controller_id = ? AND number = ?",
|
"SELECT * FROM v_relays WHERE v_relays.controller_id = ? AND v_relays.number = ?",
|
||||||
controller.id,
|
controller.id,
|
||||||
number
|
number
|
||||||
)
|
)
|
||||||
|
@ -72,7 +73,7 @@ impl DbRelay {
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
tag: &DbTag,
|
tag: &DbTag,
|
||||||
) -> Result<Vec<DbRelay>, DatabaseError> {
|
) -> Result<Vec<DbRelay>, DatabaseError> {
|
||||||
sqlx::query_as!(DbRelay, "SELECT relay.* FROM relays AS relay INNER JOIN junction_tag ON junction_tag.relay_id = relay.id WHERE junction_tag.tag_id = ?", tag.id)
|
sqlx::query_as!(DbRelay, "SELECT v_relays.* FROM v_relays INNER JOIN junction_tag ON junction_tag.relay_id = v_relays.id WHERE junction_tag.tag_id = ?", tag.id)
|
||||||
.fetch_all(conn.deref_mut())
|
.fetch_all(conn.deref_mut())
|
||||||
.await
|
.await
|
||||||
.map_err(DatabaseError::from)
|
.map_err(DatabaseError::from)
|
||||||
|
@ -84,16 +85,25 @@ impl DbRelay {
|
||||||
new_number: i64,
|
new_number: i64,
|
||||||
new_controller: &DbController,
|
new_controller: &DbController,
|
||||||
) -> Result<DbRelay, DatabaseError> {
|
) -> Result<DbRelay, DatabaseError> {
|
||||||
sqlx::query_as!(
|
let result = sqlx::query!(
|
||||||
DbRelay,
|
"INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?)",
|
||||||
"INSERT INTO relays (name, number, controller_id) VALUES (?, ?, ?) RETURNING *",
|
|
||||||
new_name,
|
new_name,
|
||||||
new_number,
|
new_number,
|
||||||
new_controller.id,
|
new_controller.id,
|
||||||
)
|
)
|
||||||
.fetch_optional(conn.deref_mut())
|
.execute(conn.deref_mut())
|
||||||
.await?
|
.await?;
|
||||||
.ok_or(DatabaseError::InsertGetError)
|
|
||||||
|
let last_insert_id = result.last_insert_rowid();
|
||||||
|
|
||||||
|
sqlx::query_as!(
|
||||||
|
DbRelay,
|
||||||
|
"SELECT * FROM v_relays WHERE id = ?",
|
||||||
|
last_insert_id
|
||||||
|
)
|
||||||
|
.fetch_one(conn.deref_mut())
|
||||||
|
.await
|
||||||
|
.map_err(DatabaseError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
pub async fn delete(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||||
|
@ -163,14 +173,4 @@ impl DbRelay {
|
||||||
.await?
|
.await?
|
||||||
.ok_or(DatabaseError::NotFound)
|
.ok_or(DatabaseError::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_active_schedule(
|
|
||||||
&self,
|
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
|
||||||
) -> Result<DbSchedule, DatabaseError> {
|
|
||||||
let weekday = utils::get_weekday();
|
|
||||||
DbJunctionRelaySchedule::get_schedule(conn, self, weekday as Weekday)
|
|
||||||
.await?
|
|
||||||
.ok_or(DatabaseError::NotFound)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
use rppal::gpio::{Gpio, OutputPin};
|
|
||||||
|
|
||||||
use crate::drivers::RelayDriver;
|
|
||||||
use crate::errors::EmgauwaError;
|
|
||||||
|
|
||||||
pub struct GpioDriver {
|
|
||||||
pub gpio: OutputPin,
|
|
||||||
pub inverted: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GpioDriver {
|
|
||||||
pub fn new(pin: u8, inverted: bool) -> Result<Self, EmgauwaError> {
|
|
||||||
let gpio = Gpio::new()?.get(pin)?.into_output();
|
|
||||||
Ok(Self { gpio, inverted })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RelayDriver for GpioDriver {
|
|
||||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError> {
|
|
||||||
if self.get_high(value) {
|
|
||||||
self.gpio.set_high();
|
|
||||||
} else {
|
|
||||||
self.gpio.set_low();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pin(&self) -> u8 {
|
|
||||||
self.gpio.pin()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inverted(&self) -> bool {
|
|
||||||
self.inverted
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
mod gpio;
|
|
||||||
mod null;
|
|
||||||
mod piface;
|
|
||||||
|
|
||||||
pub use gpio::GpioDriver;
|
|
||||||
pub use null::NullDriver;
|
|
||||||
pub use piface::PiFaceDriver;
|
|
||||||
|
|
||||||
use crate::errors::EmgauwaError;
|
|
||||||
|
|
||||||
pub trait RelayDriver {
|
|
||||||
fn get_high(&self, value: bool) -> bool {
|
|
||||||
value ^ self.get_inverted()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError>;
|
|
||||||
fn get_pin(&self) -> u8;
|
|
||||||
fn get_inverted(&self) -> bool;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
use crate::drivers::RelayDriver;
|
|
||||||
use crate::errors::EmgauwaError;
|
|
||||||
|
|
||||||
pub struct NullDriver {
|
|
||||||
pub pin: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NullDriver {
|
|
||||||
pub fn new(pin: u8) -> Self {
|
|
||||||
Self { pin }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RelayDriver for NullDriver {
|
|
||||||
fn set(&mut self, _value: bool) -> Result<(), EmgauwaError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pin(&self) -> u8 {
|
|
||||||
self.pin
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inverted(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
use rppal_pfd::{
|
|
||||||
ChipSelect, HardwareAddress, OutputPin, PiFaceDigital, PiFaceDigitalError, SpiBus, SpiMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::drivers::RelayDriver;
|
|
||||||
use crate::errors::EmgauwaError;
|
|
||||||
|
|
||||||
pub struct PiFaceDriver {
|
|
||||||
pub pfd_pin: OutputPin,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PiFaceDriver {
|
|
||||||
pub fn new(pin: u8, pfd: &Option<PiFaceDigital>) -> Result<Self, EmgauwaError> {
|
|
||||||
let pfd = pfd.as_ref().ok_or(EmgauwaError::Hardware(String::from(
|
|
||||||
"PiFaceDigital not initialized",
|
|
||||||
)))?;
|
|
||||||
let pfd_pin = pfd.get_output_pin(pin)?;
|
|
||||||
Ok(Self { pfd_pin })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_piface() -> Result<PiFaceDigital, EmgauwaError> {
|
|
||||||
let mut pfd = PiFaceDigital::new(
|
|
||||||
HardwareAddress::new(0)?,
|
|
||||||
SpiBus::Spi0,
|
|
||||||
ChipSelect::Cs0,
|
|
||||||
100_000,
|
|
||||||
SpiMode::Mode0,
|
|
||||||
)?;
|
|
||||||
pfd.init()?;
|
|
||||||
|
|
||||||
Ok(pfd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RelayDriver for PiFaceDriver {
|
|
||||||
fn set(&mut self, value: bool) -> Result<(), EmgauwaError> {
|
|
||||||
if self.get_high(value) {
|
|
||||||
self.pfd_pin.set_high().map_err(PiFaceDigitalError::from)?;
|
|
||||||
} else {
|
|
||||||
self.pfd_pin.set_low().map_err(PiFaceDigitalError::from)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pin(&self) -> u8 {
|
|
||||||
self.pfd_pin.get_pin_number()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inverted(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,9 +6,6 @@ use actix::MailboxError;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
use config::ConfigError;
|
use config::ConfigError;
|
||||||
use rppal::gpio;
|
|
||||||
use rppal_mcp23s17::Mcp23s17Error;
|
|
||||||
use rppal_pfd::PiFaceDigitalError;
|
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
@ -50,7 +47,9 @@ impl From<&EmgauwaError> for String {
|
||||||
EmgauwaError::Database(err) => String::from(err),
|
EmgauwaError::Database(err) => String::from(err),
|
||||||
EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
|
EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
|
||||||
EmgauwaError::Internal(_) => String::from("internal error"),
|
EmgauwaError::Internal(_) => String::from("internal error"),
|
||||||
EmgauwaError::Connection(_) => String::from("the target controller is not connected"),
|
EmgauwaError::Connection(uid) => {
|
||||||
|
format!("unable to connect to controller with uid: {}", uid)
|
||||||
|
}
|
||||||
EmgauwaError::Other(err) => format!("other error: {}", err),
|
EmgauwaError::Other(err) => format!("other error: {}", err),
|
||||||
EmgauwaError::Hardware(err) => format!("hardware error: {}", err),
|
EmgauwaError::Hardware(err) => format!("hardware error: {}", err),
|
||||||
}
|
}
|
||||||
|
@ -99,25 +98,6 @@ impl From<ConfigError> for EmgauwaError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<gpio::Error> for EmgauwaError {
|
|
||||||
fn from(value: gpio::Error) -> Self {
|
|
||||||
Self::Hardware(value.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PiFaceDigitalError> for EmgauwaError {
|
|
||||||
fn from(value: PiFaceDigitalError) -> Self {
|
|
||||||
match value {
|
|
||||||
PiFaceDigitalError::Mcp23s17Error { source } => match source {
|
|
||||||
Mcp23s17Error::SpiError { source } => Self::Hardware(source.to_string()),
|
|
||||||
_ => Self::Hardware(source.to_string()),
|
|
||||||
},
|
|
||||||
PiFaceDigitalError::GpioError { source } => Self::Hardware(source.to_string()),
|
|
||||||
_ => Self::Hardware(value.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&EmgauwaError> for HttpResponse {
|
impl From<&EmgauwaError> for HttpResponse {
|
||||||
fn from(err: &EmgauwaError) -> Self {
|
fn from(err: &EmgauwaError) -> Self {
|
||||||
HttpResponse::build(err.get_code()).json(err)
|
HttpResponse::build(err.get_code()).json(err)
|
||||||
|
@ -139,7 +119,7 @@ impl Serialize for EmgauwaError {
|
||||||
{
|
{
|
||||||
let mut s = serializer.serialize_struct("error", 2)?;
|
let mut s = serializer.serialize_struct("error", 2)?;
|
||||||
s.serialize_field("code", &self.get_code().as_u16())?;
|
s.serialize_field("code", &self.get_code().as_u16())?;
|
||||||
s.serialize_field("description", &String::from(self))?;
|
s.serialize_field("message", &String::from(self))?;
|
||||||
s.end()
|
s.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
src/lib.rs
66
src/lib.rs
|
@ -1,8 +1,72 @@
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod drivers;
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod periods {
|
||||||
|
use chrono::NaiveTime;
|
||||||
|
use crate::db::Period;
|
||||||
|
use crate::types::EmgauwaNow;
|
||||||
|
|
||||||
|
const MIDNIGHT: NaiveTime = NaiveTime::MIN;
|
||||||
|
|
||||||
|
fn new_time(hour: u32, minute: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_hms_opt(hour, minute, 0).expect("Failed to create NaiveTime")
|
||||||
|
}
|
||||||
|
fn new_period(start_hour: u32, start_minute: u32, end_hour: u32, end_minute: u32) -> Period {
|
||||||
|
Period {
|
||||||
|
start: new_time(start_hour, start_minute),
|
||||||
|
end: new_time(end_hour, end_minute),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn always_on() {
|
||||||
|
let period = Period::new_on();
|
||||||
|
let now: EmgauwaNow = EmgauwaNow::now(&MIDNIGHT);
|
||||||
|
assert_eq!(period.is_always_on(), true);
|
||||||
|
assert_eq!(period.is_on(&MIDNIGHT), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(12, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&now.time), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_period() {
|
||||||
|
let period = new_period(11, 00, 13, 00);
|
||||||
|
assert_eq!(period.is_always_on(), false);
|
||||||
|
assert_eq!(period.is_on(&MIDNIGHT), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(10, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(11, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(12, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(13, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(14, 00)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_midnight_period() {
|
||||||
|
let period = new_period(22, 00, 00, 00);
|
||||||
|
assert_eq!(period.is_always_on(), false);
|
||||||
|
assert_eq!(period.is_on(&MIDNIGHT), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(21, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(22, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(23, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(00, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(01, 00)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_midnight_period() {
|
||||||
|
let period = new_period(00, 00, 02, 00);
|
||||||
|
assert_eq!(period.is_always_on(), false);
|
||||||
|
assert_eq!(period.is_on(&MIDNIGHT), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(23, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(00, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(01, 00)), true);
|
||||||
|
assert_eq!(period.is_on(&new_time(02, 00)), false);
|
||||||
|
assert_eq!(period.is_on(&new_time(03, 00)), false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::DbController;
|
use crate::db::DbController;
|
||||||
use crate::errors::{DatabaseError, EmgauwaError};
|
use crate::errors::{DatabaseError, EmgauwaError};
|
||||||
use crate::models::{convert_db_list_cache, FromDbModel, Relay};
|
use crate::models::{convert_db_list, FromDbModel, Relay};
|
||||||
use crate::types::RelayStates;
|
use crate::types::{EmgauwaNow, RelayState, RelayStates};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
|
@ -28,7 +28,7 @@ impl FromDbModel for Controller {
|
||||||
db_model: Self::DbModel,
|
db_model: Self::DbModel,
|
||||||
) -> Result<Self, DatabaseError> {
|
) -> Result<Self, DatabaseError> {
|
||||||
let relays_db = block_on(db_model.get_relays(conn))?;
|
let relays_db = block_on(db_model.get_relays(conn))?;
|
||||||
let cache = convert_db_list_cache(conn, relays_db, db_model.clone())?;
|
let cache = convert_db_list(conn, relays_db)?;
|
||||||
Self::from_db_model_cache(conn, db_model, cache)
|
Self::from_db_model_cache(conn, db_model, cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,19 +57,20 @@ impl Controller {
|
||||||
self.relays
|
self.relays
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(relay_states.iter())
|
.zip(relay_states.iter())
|
||||||
.for_each(|(relay, is_on)| {
|
.for_each(|(relay, state)| relay.apply_state(state));
|
||||||
relay.is_on = *is_on;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_relay_states(&self) -> RelayStates {
|
pub fn get_relay_states(&self) -> RelayStates {
|
||||||
self.relays.iter().map(|r| r.is_on).collect()
|
self.relays.iter().map(RelayState::from).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
pub fn check_next_time(&mut self, now: &EmgauwaNow) -> Option<NaiveTime> {
|
||||||
self.relays
|
self.relays
|
||||||
.iter()
|
.iter_mut()
|
||||||
.filter_map(|r| r.active_schedule.get_next_time(now))
|
.filter_map(|r| {
|
||||||
|
r.reload_active_schedule(now.weekday);
|
||||||
|
r.get_next_time(&now.time)
|
||||||
|
})
|
||||||
.min()
|
.min()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +81,8 @@ impl Controller {
|
||||||
.find(|r| r.r.number == relay_num)
|
.find(|r| r.r.number == relay_num)
|
||||||
.ok_or(EmgauwaError::Other(String::from("Relay not found")))?;
|
.ok_or(EmgauwaError::Other(String::from("Relay not found")))?;
|
||||||
|
|
||||||
|
log::debug!("Pulsing relay {} until {:?}", relay_num, until);
|
||||||
|
|
||||||
relay.pulsing = Some(until);
|
relay.pulsing = Some(until);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ use serde_derive::{Deserialize, Serialize};
|
||||||
use sqlx::pool::PoolConnection;
|
use sqlx::pool::PoolConnection;
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::{DbJunctionRelaySchedule, DbMacroAction};
|
use crate::db::{DbJunctionRelaySchedule, DbMacroAction, DbSchedule};
|
||||||
use crate::errors::{DatabaseError, EmgauwaError};
|
use crate::errors::{DatabaseError, EmgauwaError};
|
||||||
use crate::models::{FromDbModel, Relay, Schedule};
|
use crate::models::{FromDbModel, Relay};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MacroAction {
|
pub struct MacroAction {
|
||||||
pub schedule: Schedule,
|
pub schedule: DbSchedule,
|
||||||
pub relay: Relay,
|
pub relay: Relay,
|
||||||
pub weekday: i64,
|
pub weekday: i64,
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ impl FromDbModel for MacroAction {
|
||||||
db_model: Self::DbModel,
|
db_model: Self::DbModel,
|
||||||
_cache: Self::DbModelCache,
|
_cache: Self::DbModelCache,
|
||||||
) -> Result<Self, DatabaseError> {
|
) -> Result<Self, DatabaseError> {
|
||||||
let schedule_db = block_on(db_model.get_schedule(conn))?;
|
let schedule = block_on(db_model.get_schedule(conn))?;
|
||||||
let schedule = Schedule::from_db_model(conn, schedule_db)?;
|
|
||||||
|
|
||||||
let relay_db = block_on(db_model.get_relay(conn))?;
|
let relay_db = block_on(db_model.get_relay(conn))?;
|
||||||
let relay = Relay::from_db_model(conn, relay_db)?;
|
let relay = Relay::from_db_model(conn, relay_db)?;
|
||||||
|
@ -48,7 +47,7 @@ impl FromDbModel for MacroAction {
|
||||||
|
|
||||||
impl MacroAction {
|
impl MacroAction {
|
||||||
pub async fn execute(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
pub async fn execute(&self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> {
|
||||||
DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule.s, self.weekday)
|
DbJunctionRelaySchedule::set_schedule(conn, &self.relay.r, &self.schedule, self.weekday)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,65 @@
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use chrono::NaiveTime;
|
use chrono::{NaiveTime, Weekday};
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use sqlx::pool::PoolConnection;
|
use sqlx::pool::PoolConnection;
|
||||||
use sqlx::Sqlite;
|
use sqlx::Sqlite;
|
||||||
|
|
||||||
use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
|
use crate::db::{DbJunctionRelaySchedule, DbRelay, DbSchedule};
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::models::FromDbModel;
|
use crate::models::FromDbModel;
|
||||||
use crate::types::EmgauwaUid;
|
use crate::types::RelayState;
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Relay {
|
pub struct Relay {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub r: DbRelay,
|
pub r: DbRelay,
|
||||||
pub controller: DbController,
|
|
||||||
pub controller_id: EmgauwaUid,
|
|
||||||
pub schedules: Vec<DbSchedule>,
|
pub schedules: Vec<DbSchedule>,
|
||||||
pub active_schedule: DbSchedule,
|
pub active_schedule: Option<DbSchedule>,
|
||||||
|
pub override_schedule: Option<DbSchedule>,
|
||||||
pub is_on: Option<bool>,
|
pub is_on: Option<bool>,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
|
|
||||||
// for internal use only.
|
// for internal use only.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub pulsing: Option<Instant>,
|
pub pulsing: Option<Instant>,
|
||||||
|
#[serde(skip, default = "utils::default_weekday")]
|
||||||
|
pub override_schedule_weekday: Weekday,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromDbModel for Relay {
|
impl FromDbModel for Relay {
|
||||||
type DbModel = DbRelay;
|
type DbModel = DbRelay;
|
||||||
type DbModelCache = DbController;
|
type DbModelCache = ();
|
||||||
|
|
||||||
fn from_db_model(
|
fn from_db_model(
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
db_model: Self::DbModel,
|
db_model: Self::DbModel,
|
||||||
) -> Result<Self, DatabaseError> {
|
) -> Result<Self, DatabaseError> {
|
||||||
let cache = block_on(db_model.get_controller(conn))?;
|
Self::from_db_model_cache(conn, db_model, ())
|
||||||
Self::from_db_model_cache(conn, db_model, cache)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_db_model_cache(
|
fn from_db_model_cache(
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
conn: &mut PoolConnection<Sqlite>,
|
||||||
db_model: Self::DbModel,
|
db_model: Self::DbModel,
|
||||||
cache: Self::DbModelCache,
|
_cache: Self::DbModelCache,
|
||||||
) -> Result<Self, DatabaseError> {
|
) -> Result<Self, DatabaseError> {
|
||||||
let tags = block_on(db_model.get_tags(conn))?;
|
let tags = block_on(db_model.get_tags(conn))?;
|
||||||
let controller_id = cache.uid.clone();
|
|
||||||
|
|
||||||
let schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &db_model))?;
|
let schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &db_model))?;
|
||||||
let active_schedule = block_on(db_model.get_active_schedule(conn))?;
|
|
||||||
|
|
||||||
let is_on = None;
|
let is_on = None;
|
||||||
|
|
||||||
Ok(Relay {
|
Ok(Relay {
|
||||||
r: db_model,
|
r: db_model,
|
||||||
controller: cache,
|
|
||||||
controller_id,
|
|
||||||
schedules,
|
schedules,
|
||||||
active_schedule,
|
active_schedule: None,
|
||||||
|
override_schedule: None,
|
||||||
is_on,
|
is_on,
|
||||||
tags,
|
tags,
|
||||||
pulsing: None,
|
pulsing: None,
|
||||||
|
override_schedule_weekday: utils::default_weekday(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,25 +68,24 @@ impl Relay {
|
||||||
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> {
|
||||||
self.r = block_on(self.r.reload(conn))?;
|
self.r = block_on(self.r.reload(conn))?;
|
||||||
self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?;
|
self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?;
|
||||||
self.reload_active_schedule(conn)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload_active_schedule(
|
|
||||||
&mut self,
|
|
||||||
conn: &mut PoolConnection<Sqlite>,
|
|
||||||
) -> Result<(), DatabaseError> {
|
|
||||||
self.active_schedule = block_on(self.r.get_active_schedule(conn))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
pub fn is_on(&self, now: &NaiveTime) -> bool {
|
||||||
self.active_schedule.is_on(now)
|
if let Some(active_schedule) = &self.active_schedule {
|
||||||
|
active_schedule.is_on(now)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> {
|
||||||
self.active_schedule.get_next_time(now)
|
if let Some(active_schedule) = &self.active_schedule {
|
||||||
|
active_schedule.get_next_time(now)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_pulsing(&mut self, now: &Instant) -> Option<Instant> {
|
pub fn check_pulsing(&mut self, now: &Instant) -> Option<Instant> {
|
||||||
|
@ -103,4 +101,32 @@ impl Relay {
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reload_active_schedule(&mut self, weekday: Weekday) {
|
||||||
|
if let Some(schedule) = &self.override_schedule {
|
||||||
|
if self.override_schedule_weekday == weekday {
|
||||||
|
self.active_schedule = Some(schedule.clone());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.override_schedule_weekday != weekday {
|
||||||
|
self.override_schedule = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(schedule) = self.schedules.get(weekday as usize) {
|
||||||
|
self.active_schedule = Some(schedule.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_state(&mut self, state: &RelayState) {
|
||||||
|
self.active_schedule.clone_from(&state.active_schedule);
|
||||||
|
self.override_schedule.clone_from(&state.override_schedule);
|
||||||
|
self.is_on = state.is_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_and_apply_state(&mut self, stated_relays: &[Relay]) {
|
||||||
|
if let Some(stated_relay) = stated_relays.iter().find(|r| r.r.id == self.r.id) {
|
||||||
|
self.apply_state(&stated_relay.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ pub struct Server {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct Logging {
|
pub struct Logging {
|
||||||
pub level: String,
|
pub level: String,
|
||||||
pub file: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Default)]
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
|
@ -40,7 +39,6 @@ impl Default for Logging {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Logging {
|
Logging {
|
||||||
level: String::from("info"),
|
level: String::from("info"),
|
||||||
file: String::from("stdout"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
src/types/emgauwa_now.rs
Normal file
27
src/types/emgauwa_now.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use chrono::{Local, NaiveTime, Timelike, Weekday};
|
||||||
|
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
pub struct EmgauwaNow {
|
||||||
|
pub time: NaiveTime,
|
||||||
|
pub instant: Instant,
|
||||||
|
pub weekday: Weekday,
|
||||||
|
pub midnight: NaiveTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmgauwaNow {
|
||||||
|
pub fn now(midnight: &NaiveTime) -> EmgauwaNow {
|
||||||
|
EmgauwaNow {
|
||||||
|
time: Local::now().time(),
|
||||||
|
instant: Instant::now(),
|
||||||
|
weekday: utils::get_weekday(midnight),
|
||||||
|
midnight: *midnight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_seconds_from_midnight(&self) -> u32 {
|
||||||
|
self.time.num_seconds_from_midnight()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,13 @@
|
||||||
|
mod emgauwa_now;
|
||||||
mod emgauwa_uid;
|
mod emgauwa_uid;
|
||||||
mod request;
|
mod request;
|
||||||
mod schedule_uid;
|
mod schedule_uid;
|
||||||
|
mod relay_state;
|
||||||
|
|
||||||
use actix::Message;
|
use actix::Message;
|
||||||
|
pub use emgauwa_now::EmgauwaNow;
|
||||||
pub use emgauwa_uid::EmgauwaUid;
|
pub use emgauwa_uid::EmgauwaUid;
|
||||||
|
pub use relay_state::{RelayState, RelayStates};
|
||||||
pub use request::*;
|
pub use request::*;
|
||||||
pub use schedule_uid::ScheduleUid;
|
pub use schedule_uid::ScheduleUid;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -12,10 +16,6 @@ use crate::db::DbSchedule;
|
||||||
use crate::errors::EmgauwaError;
|
use crate::errors::EmgauwaError;
|
||||||
use crate::models::{Controller, Relay};
|
use crate::models::{Controller, Relay};
|
||||||
|
|
||||||
pub type Weekday = i64;
|
|
||||||
|
|
||||||
pub type RelayStates = Vec<Option<bool>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Message)]
|
#[derive(Debug, Serialize, Deserialize, Message)]
|
||||||
#[rtype(result = "Result<(), EmgauwaError>")]
|
#[rtype(result = "Result<(), EmgauwaError>")]
|
||||||
pub enum ControllerWsAction {
|
pub enum ControllerWsAction {
|
||||||
|
|
22
src/types/relay_state.rs
Normal file
22
src/types/relay_state.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use crate::db::DbSchedule;
|
||||||
|
use crate::models::Relay;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct RelayState {
|
||||||
|
pub active_schedule: Option<DbSchedule>,
|
||||||
|
pub override_schedule: Option<DbSchedule>,
|
||||||
|
pub is_on: Option<bool>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RelayStates = Vec<RelayState>;
|
||||||
|
|
||||||
|
impl From<&Relay> for RelayState {
|
||||||
|
fn from(relay: &Relay) -> Self {
|
||||||
|
RelayState {
|
||||||
|
active_schedule: relay.active_schedule.clone(),
|
||||||
|
override_schedule: relay.override_schedule.clone(),
|
||||||
|
is_on: relay.is_on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,11 +23,21 @@ pub struct RequestScheduleUpdate {
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct RequestRelayUpdate {
|
pub struct RequestRelayUpdate {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub active_schedule: Option<RequestScheduleId>,
|
#[serde(
|
||||||
|
default, // <- important for deserialization
|
||||||
|
skip_serializing_if = "Option::is_none", // <- important for serialization
|
||||||
|
with = "::serde_with::rust::double_option",
|
||||||
|
)]
|
||||||
|
pub override_schedule: Option<Option<RequestScheduleId>>,
|
||||||
pub schedules: Option<Vec<RequestScheduleId>>,
|
pub schedules: Option<Vec<RequestScheduleId>>,
|
||||||
pub tags: Option<Vec<String>>,
|
pub tags: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct RequestScheduleGetTagged {
|
||||||
|
pub strict: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct RequestRelayPulse {
|
pub struct RequestRelayPulse {
|
||||||
pub duration: Option<u32>,
|
pub duration: Option<u32>,
|
||||||
|
|
32
src/utils.rs
32
src/utils.rs
|
@ -2,17 +2,17 @@ use std::ffi::CString;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use chrono::Datelike;
|
use chrono::{Datelike, NaiveTime, Weekday};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
use crate::errors::EmgauwaError;
|
use crate::errors::EmgauwaError;
|
||||||
use crate::settings::Permissions;
|
use crate::settings::{Logging, Permissions};
|
||||||
use crate::types::{RelayStates, Weekday};
|
use crate::types::RelayStates;
|
||||||
|
|
||||||
pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
|
pub fn init_logging(logging: &Logging) -> Result<(), EmgauwaError> {
|
||||||
let log_level: LevelFilter = LevelFilter::from_str(level)
|
let log_level: LevelFilter = LevelFilter::from_str(&logging.level)
|
||||||
.map_err(|_| EmgauwaError::Other(format!("Invalid log level: {}", level)))?;
|
.map_err(|_| EmgauwaError::Other(format!("Invalid log level: {}", logging.level)))?;
|
||||||
log::trace!("Log level set to {:?}", log_level);
|
log::trace!("Log level set to {:?}", log_level);
|
||||||
|
|
||||||
SimpleLogger::new()
|
SimpleLogger::new()
|
||||||
|
@ -92,18 +92,24 @@ fn drop_privileges_user(user: &str) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_weekday() -> Weekday {
|
pub fn get_weekday(midnight: &NaiveTime) -> Weekday {
|
||||||
(chrono::offset::Local::now()
|
let dt = chrono::offset::Local::now().naive_local();
|
||||||
.date_naive()
|
let weekday = dt.weekday();
|
||||||
.weekday()
|
if dt.time().lt(midnight) {
|
||||||
.number_from_monday()
|
weekday.pred()
|
||||||
- 1) as Weekday
|
} else {
|
||||||
|
weekday
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_weekday() -> Weekday {
|
||||||
|
Weekday::Mon
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn printable_relay_states(relay_states: &RelayStates) -> String {
|
pub fn printable_relay_states(relay_states: &RelayStates) -> String {
|
||||||
let mut relay_debug = String::new();
|
let mut relay_debug = String::new();
|
||||||
relay_states.iter().for_each(|state| {
|
relay_states.iter().for_each(|state| {
|
||||||
relay_debug.push_str(match state {
|
relay_debug.push_str(match state.is_on {
|
||||||
Some(true) => "+",
|
Some(true) => "+",
|
||||||
Some(false) => "-",
|
Some(false) => "-",
|
||||||
None => "?",
|
None => "?",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue