2023-10-23 08:03:16 +00:00
|
|
|
use std::{path::Path, str::FromStr};
|
2023-09-19 08:52:12 +00:00
|
|
|
|
|
|
|
use anyhow::Result;
|
2023-10-05 08:08:57 +00:00
|
|
|
use rusqlite::{Connection, OptionalExtension, ToSql};
|
2023-09-19 08:52:12 +00:00
|
|
|
|
2023-10-23 08:03:16 +00:00
|
|
|
use crate::{
|
2023-10-23 09:07:37 +00:00
|
|
|
action::{Action, ActionID, ActionSet, ActionType},
|
2023-10-23 08:03:16 +00:00
|
|
|
devices::{DeviceWithName, Devices, DevicesWithName},
|
|
|
|
};
|
2023-09-21 08:08:23 +00:00
|
|
|
|
2023-09-19 08:52:12 +00:00
|
|
|
pub struct DataBase {
|
|
|
|
sql: Connection,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DataBase {
|
2023-09-21 08:08:23 +00:00
|
|
|
const VERSION_0_1_0: &'static str = "0.1.0";
|
|
|
|
|
2023-09-19 08:52:12 +00:00
|
|
|
pub async fn new(path: impl AsRef<Path>) -> Result<Self> {
|
|
|
|
let me = Self {
|
|
|
|
sql: Connection::open(path)?,
|
|
|
|
};
|
|
|
|
|
|
|
|
me.generate_tables()?;
|
2023-09-21 08:08:23 +00:00
|
|
|
me.init()?;
|
2023-09-19 08:52:12 +00:00
|
|
|
|
|
|
|
Ok(me)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_tables(&self) -> Result<()> {
|
2023-09-19 09:18:22 +00:00
|
|
|
self.sql.execute(
|
2023-09-21 08:08:23 +00:00
|
|
|
"CREATE TABLE IF NOT EXISTS meta (
|
|
|
|
id INTEGER PRIMARY KEY,
|
|
|
|
version INTEGER NOT NULL
|
|
|
|
)",
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
|
|
|
|
self.sql.execute(
|
2023-10-19 14:26:09 +00:00
|
|
|
"CREATE TABLE IF NOT EXISTS devices (
|
2023-09-19 09:18:22 +00:00
|
|
|
id INTEGER PRIMARY KEY,
|
2023-09-21 08:08:23 +00:00
|
|
|
device VARCHAR(60) NOT NULL,
|
|
|
|
type VARCHAR(30) NOT NULL,
|
2023-09-22 05:43:56 +00:00
|
|
|
control INTEGER NOT NULL,
|
2023-09-21 08:08:23 +00:00
|
|
|
name VARCHAR(80)
|
2023-09-19 09:18:22 +00:00
|
|
|
)",
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
self.sql.execute(
|
|
|
|
"CREATE TABLE IF NOT EXISTS data (
|
|
|
|
id INTEGER PRIMARY KEY,
|
|
|
|
time BIGINT NOT NULL,
|
2023-10-19 14:26:09 +00:00
|
|
|
name VARCHAR(30) NOT NULL,
|
|
|
|
value REAL NOT NULL,
|
2023-09-21 08:08:23 +00:00
|
|
|
device_id INTEGER NOT NULL,
|
|
|
|
FOREIGN KEY(device_id) REFERENCES devices(id)
|
|
|
|
)",
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
|
2023-10-05 08:08:57 +00:00
|
|
|
self.sql.execute(
|
|
|
|
"CREATE TABLE IF NOT EXISTS credentials (
|
|
|
|
id INTEGER PRIMARY KEY,
|
|
|
|
key VARCHAR(60) NOT NULL,
|
|
|
|
device_id BIGINT NOT NULL,
|
|
|
|
cred VARCHAR(256) NOT NULL
|
|
|
|
)",
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
|
2023-10-23 08:03:16 +00:00
|
|
|
self.sql.execute(
|
|
|
|
"
|
|
|
|
CREATE TABLE IF NOT EXISTS actions (
|
|
|
|
id INTEGER PRIMARY KEY,
|
|
|
|
device_id INTEGER NOT NULL,
|
|
|
|
action VARCHAR(30) NOT NULL,
|
|
|
|
parameter VARCHAR(60) NOT NULL,
|
|
|
|
action_id INTEGER,
|
|
|
|
FOREIGN KEY(action_id) REFERENCES actions(id),
|
|
|
|
FOREIGN KEY(device_id) REFERENCES devices(id)
|
|
|
|
)
|
|
|
|
",
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-10-23 08:03:16 +00:00
|
|
|
fn device_id(&self, device_name: &str) -> Result<i64> {
|
|
|
|
Ok(self
|
|
|
|
.sql
|
|
|
|
.prepare(&format!(
|
|
|
|
"
|
|
|
|
SELECT id
|
|
|
|
FROM devices
|
|
|
|
WHERE device=\"{}\"
|
|
|
|
",
|
|
|
|
device_name
|
|
|
|
))?
|
|
|
|
.query_row([], |row| Ok(row.get(0)?))?)
|
|
|
|
}
|
|
|
|
|
2023-10-23 09:07:37 +00:00
|
|
|
pub fn insert_action_set(&self, action_set: ActionSet) -> Result<ActionID> {
|
2023-10-23 08:03:16 +00:00
|
|
|
let mut action_ids = Vec::new();
|
|
|
|
|
|
|
|
for (i, action) in action_set.iter().enumerate() {
|
|
|
|
// get device id from device name
|
|
|
|
let device_id = self.device_id(&action.device_id)?;
|
|
|
|
|
|
|
|
// insert action to DB
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"INSERT INTO actions (device_id, action, parameter)
|
|
|
|
VALUES (?1, \"{}\", \"{}\")",
|
|
|
|
action.action_type, action.parameter
|
|
|
|
),
|
|
|
|
&[&device_id],
|
|
|
|
)?;
|
|
|
|
|
|
|
|
action_ids.push(self.sql.last_insert_rowid());
|
|
|
|
|
|
|
|
if i > 0 {
|
|
|
|
// chain actions
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"
|
|
|
|
UPDATE actions
|
|
|
|
SET action_id=?2
|
|
|
|
WHERE id=?1
|
|
|
|
"
|
|
|
|
),
|
|
|
|
[&action_ids[i - 1], &action_ids[i]],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 09:07:37 +00:00
|
|
|
Ok(ActionID(action_ids[0]))
|
2023-10-23 08:03:16 +00:00
|
|
|
}
|
|
|
|
|
2023-10-23 09:07:37 +00:00
|
|
|
pub fn remove_action_set(&self, action_set: &ActionSet) -> Result<()> {
|
|
|
|
if let Some(action_id) = action_set.first_id() {
|
|
|
|
self.sql.execute(
|
|
|
|
"
|
|
|
|
DELETE FROM actions
|
|
|
|
WHERE id=?1
|
|
|
|
",
|
|
|
|
&[&action_id.0],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn action_set(&self, mut action_id: ActionID) -> Result<ActionSet> {
|
2023-10-23 08:03:16 +00:00
|
|
|
let mut action_set = ActionSet::default();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let (device_id, action, parameter, next_action): (i64, String, String, Option<i64>) =
|
|
|
|
self.sql.query_row(
|
|
|
|
"
|
|
|
|
SELECT device_id, action, parameter, action_id
|
|
|
|
FROM actions
|
|
|
|
WHERE id=?1
|
|
|
|
",
|
2023-10-23 09:07:37 +00:00
|
|
|
&[&action_id.0],
|
2023-10-23 08:03:16 +00:00
|
|
|
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let device_name: String = self.sql.query_row(
|
|
|
|
"
|
|
|
|
SELECT device
|
|
|
|
FROM devices
|
|
|
|
WHERE id=?1
|
|
|
|
",
|
|
|
|
&[&device_id],
|
|
|
|
|row| row.get(0),
|
|
|
|
)?;
|
|
|
|
|
2023-10-23 09:07:37 +00:00
|
|
|
let mut action = Action::new(device_name, ActionType::from_str(&action)?, parameter);
|
|
|
|
action.id = Some(action_id);
|
2023-10-23 08:03:16 +00:00
|
|
|
|
|
|
|
action_set.chain(action);
|
|
|
|
|
|
|
|
match next_action {
|
2023-10-23 09:07:37 +00:00
|
|
|
Some(id) => action_id.0 = id,
|
2023-10-23 08:03:16 +00:00
|
|
|
None => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(action_set)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn action_sets(&self, device_name: &str) -> Result<Vec<ActionSet>> {
|
|
|
|
let mut action_sets = Vec::new();
|
|
|
|
|
|
|
|
let device_id = self.device_id(device_name)?;
|
|
|
|
|
|
|
|
let base_actions: Vec<i64> = self
|
|
|
|
.sql
|
|
|
|
.prepare(
|
|
|
|
"
|
|
|
|
SELECT id
|
|
|
|
FROM actions
|
|
|
|
WHERE device_id=?1
|
|
|
|
",
|
|
|
|
)?
|
|
|
|
.query_map(&[&device_id], |row| row.get(0))?
|
|
|
|
.map(|row| {
|
|
|
|
let r: i64 = row?;
|
|
|
|
Ok(r)
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<i64>>>()?;
|
|
|
|
|
|
|
|
for mut action_id in base_actions {
|
|
|
|
loop {
|
|
|
|
match self
|
|
|
|
.sql
|
|
|
|
.query_row(
|
|
|
|
"
|
|
|
|
SELECT id
|
|
|
|
FROM actions
|
|
|
|
WHERE action_id=?1
|
|
|
|
",
|
|
|
|
&[&action_id],
|
|
|
|
|row| row.get(0),
|
|
|
|
)
|
|
|
|
.optional()?
|
|
|
|
{
|
|
|
|
Some(id) => action_id = id,
|
|
|
|
None => {
|
2023-10-23 09:07:37 +00:00
|
|
|
action_sets.push(self.action_set(ActionID(action_id))?);
|
2023-10-23 08:03:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(action_sets)
|
|
|
|
}
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
pub fn version(&self) -> Result<String> {
|
|
|
|
Ok(self
|
|
|
|
.sql
|
|
|
|
.query_row("SELECT version FROM meta WHERE id=1", [], |row| row.get(0))?)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init(&self) -> Result<()> {
|
|
|
|
if self.version().is_err() {
|
|
|
|
self.sql.execute(
|
|
|
|
"INSERT INTO meta (version)
|
|
|
|
VALUES (?1)",
|
|
|
|
&[Self::VERSION_0_1_0],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register_devices(&self, devices: &Devices) -> Result<()> {
|
2023-09-22 05:43:56 +00:00
|
|
|
for (device, control) in devices.plugs.iter() {
|
2023-09-21 08:08:23 +00:00
|
|
|
self.sql.execute(
|
2023-09-21 08:46:23 +00:00
|
|
|
&format!(
|
2023-10-03 06:22:21 +00:00
|
|
|
"INSERT INTO devices (device, type, control)
|
|
|
|
SELECT \"{device}\", \"plug\", ?1
|
2023-09-21 08:08:23 +00:00
|
|
|
WHERE
|
|
|
|
NOT EXISTS (
|
|
|
|
SELECT device
|
|
|
|
FROM devices
|
2023-09-21 08:46:23 +00:00
|
|
|
WHERE device=\"{device}\"
|
2023-09-21 08:08:23 +00:00
|
|
|
)
|
2023-09-21 08:46:23 +00:00
|
|
|
"
|
|
|
|
),
|
2023-10-03 06:22:21 +00:00
|
|
|
&[control],
|
2023-09-21 08:08:23 +00:00
|
|
|
)?;
|
2023-09-22 05:43:56 +00:00
|
|
|
|
|
|
|
let ctl = if *control { 1 } else { 0 };
|
|
|
|
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"
|
|
|
|
UPDATE devices
|
|
|
|
SET control=\"{ctl}\"
|
|
|
|
WHERE device=\"{device}\"
|
|
|
|
"
|
|
|
|
),
|
|
|
|
[],
|
|
|
|
)?;
|
2023-09-21 08:08:23 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
for device in devices.thermostat.iter() {
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"INSERT INTO devices (device, type, control)
|
|
|
|
SELECT \"{device}\", \"thermostat\", false
|
|
|
|
WHERE
|
|
|
|
NOT EXISTS (
|
|
|
|
SELECT device
|
|
|
|
FROM devices
|
|
|
|
WHERE device=\"{device}\"
|
|
|
|
)
|
|
|
|
"
|
|
|
|
),
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for device in devices.thermometer.iter() {
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"INSERT INTO devices (device, type, control)
|
|
|
|
SELECT \"{device}\", \"thermometer\", false
|
|
|
|
WHERE
|
|
|
|
NOT EXISTS (
|
|
|
|
SELECT device
|
|
|
|
FROM devices
|
|
|
|
WHERE device=\"{device}\"
|
|
|
|
)
|
|
|
|
"
|
|
|
|
),
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2023-09-19 09:18:22 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
pub fn write(&self, device_name: &str, time: u64, name: &str, value: f32) -> Result<()> {
|
|
|
|
let params: &[&dyn ToSql] = &[&time, &value];
|
2023-09-19 09:18:22 +00:00
|
|
|
|
|
|
|
self.sql.execute(
|
2023-09-21 08:08:23 +00:00
|
|
|
&format!(
|
2023-10-19 14:26:09 +00:00
|
|
|
"INSERT INTO data (time, name, value, device_id)
|
|
|
|
VALUES (?1, \"{name}\", ?2, (SELECT id FROM devices WHERE device=\"{device_name}\") )"
|
2023-09-21 08:08:23 +00:00
|
|
|
),
|
2023-09-19 09:18:22 +00:00
|
|
|
params,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2023-09-20 10:19:41 +00:00
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
pub fn devices(&self) -> Result<DevicesWithName> {
|
|
|
|
let mut devices = DevicesWithName::default();
|
|
|
|
|
|
|
|
for row in self
|
|
|
|
.sql
|
|
|
|
.prepare(&format!(
|
|
|
|
"
|
2023-09-22 05:43:56 +00:00
|
|
|
SELECT device, type, name, control
|
2023-09-21 08:08:23 +00:00
|
|
|
FROM devices
|
|
|
|
"
|
|
|
|
))?
|
2023-09-22 05:43:56 +00:00
|
|
|
.query_map([], |row| {
|
|
|
|
Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
|
|
|
|
})?
|
2023-09-21 08:08:23 +00:00
|
|
|
{
|
2023-09-22 05:43:56 +00:00
|
|
|
let (device, dev_type, name, control): (String, String, Option<String>, i32) = row?;
|
2023-09-21 08:08:23 +00:00
|
|
|
|
|
|
|
match dev_type.as_str() {
|
2023-10-10 12:06:26 +00:00
|
|
|
"plug" => devices.plugs.push(DeviceWithName {
|
|
|
|
id: device,
|
|
|
|
desc: name,
|
|
|
|
toggle: control != 0,
|
|
|
|
}),
|
2023-10-19 14:26:09 +00:00
|
|
|
"thermostat" => devices.thermostat.push(DeviceWithName {
|
|
|
|
id: device,
|
|
|
|
desc: name,
|
|
|
|
toggle: control != 0,
|
|
|
|
}),
|
|
|
|
"thermometer" => devices.temperature_and_humidity.push(DeviceWithName {
|
|
|
|
id: device,
|
|
|
|
desc: name,
|
|
|
|
toggle: control != 0,
|
|
|
|
}),
|
2023-09-21 08:08:23 +00:00
|
|
|
|
|
|
|
_ => panic!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(devices)
|
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
pub fn device_exists(&self, device_id: &str) -> Result<bool> {
|
|
|
|
Ok(self
|
|
|
|
.sql
|
|
|
|
.prepare(&format!(
|
|
|
|
"
|
|
|
|
SELECT *
|
|
|
|
FROM devices
|
|
|
|
WHERE device=\"{device_id}\"
|
|
|
|
"
|
|
|
|
))?
|
|
|
|
.exists([])?)
|
|
|
|
}
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
pub fn change_device_name(&self, device: &str, description: &str) -> Result<()> {
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"
|
|
|
|
UPDATE devices
|
2023-09-21 08:46:23 +00:00
|
|
|
SET name=\"{description}\"
|
|
|
|
WHERE device=\"{device}\"
|
2023-09-21 08:08:23 +00:00
|
|
|
"
|
|
|
|
),
|
2023-09-21 08:46:23 +00:00
|
|
|
[],
|
2023-09-21 08:08:23 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-20 10:19:41 +00:00
|
|
|
pub fn read(&self, device: &str) -> Result<Vec<(u64, f32)>> {
|
2023-09-29 16:05:49 +00:00
|
|
|
self._read(&format!(
|
|
|
|
"
|
2023-10-19 14:26:09 +00:00
|
|
|
SELECT data.time, data.value
|
2023-09-29 16:05:49 +00:00
|
|
|
FROM data
|
|
|
|
INNER JOIN devices
|
|
|
|
ON data.device_id=devices.id
|
|
|
|
WHERE devices.device=\"{device}\"
|
|
|
|
"
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_range(&self, device: &str, start: u64, end: u64) -> Result<Vec<(u64, f32)>> {
|
|
|
|
self._read(&format!(
|
|
|
|
"
|
2023-10-19 14:26:09 +00:00
|
|
|
SELECT data.time, data.value
|
2023-09-29 16:05:49 +00:00
|
|
|
FROM data
|
|
|
|
INNER JOIN devices
|
|
|
|
ON data.device_id=devices.id
|
|
|
|
WHERE devices.device=\"{device}\"
|
|
|
|
AND data.time>={start}
|
|
|
|
AND data.time<{end}
|
|
|
|
"
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn _read(&self, query: &str) -> Result<Vec<(u64, f32)>> {
|
2023-09-20 10:19:41 +00:00
|
|
|
self.sql
|
2023-09-29 16:05:49 +00:00
|
|
|
.prepare(query)?
|
2023-09-20 10:19:41 +00:00
|
|
|
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
|
|
|
|
.map(|row| {
|
|
|
|
let (time, watts) = row?;
|
|
|
|
|
|
|
|
Ok((time, watts))
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
2023-10-05 08:08:57 +00:00
|
|
|
|
|
|
|
pub fn write_credential(&self, key: &str, device_id: u64, credential: &str) -> Result<()> {
|
|
|
|
if self
|
|
|
|
.sql
|
|
|
|
.prepare(&format!(
|
|
|
|
"
|
|
|
|
SELECT cred
|
|
|
|
FROM credentials
|
|
|
|
WHERE key=\"{key}\" AND device_id={device_id}
|
|
|
|
"
|
|
|
|
))?
|
|
|
|
.exists([])?
|
|
|
|
{
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"
|
|
|
|
UPDATE credentials
|
|
|
|
SET cred=\"{credential}\"
|
|
|
|
WHERE key=\"{key}\" AND device_id={device_id}
|
|
|
|
"
|
|
|
|
),
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
} else {
|
|
|
|
self.sql.execute(
|
|
|
|
&format!(
|
|
|
|
"INSERT INTO crendetials (key, device_id, cred)
|
|
|
|
VALUES (\"{key}\", {device_id}, \"{credential}\")"
|
|
|
|
),
|
|
|
|
[],
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_credential(&self, key: &str, device_id: u64) -> Result<Option<String>> {
|
|
|
|
Ok(self
|
|
|
|
.sql
|
|
|
|
.prepare(&format!(
|
|
|
|
"
|
|
|
|
SELECT cred
|
|
|
|
FROM credentials
|
|
|
|
WHERE key=\"{key}\" AND device_id={device_id}
|
|
|
|
"
|
|
|
|
))?
|
|
|
|
.query_row([], |row| Ok(row.get(0)?))
|
|
|
|
.optional()?)
|
|
|
|
}
|
2023-09-19 09:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use std::fs;
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
2023-10-23 08:03:16 +00:00
|
|
|
use crate::{
|
|
|
|
action::{Action, ActionSet, ActionType},
|
|
|
|
devices::Devices,
|
|
|
|
};
|
2023-09-21 08:08:23 +00:00
|
|
|
|
2023-09-19 09:18:22 +00:00
|
|
|
use super::DataBase;
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_connection() -> Result<()> {
|
2023-09-21 08:08:23 +00:00
|
|
|
let db = DataBase::new("connection_test.db").await?;
|
|
|
|
assert_eq!(DataBase::VERSION_0_1_0, db.version()?);
|
2023-09-19 09:18:22 +00:00
|
|
|
|
|
|
|
fs::remove_file("connection_test.db")?;
|
|
|
|
|
|
|
|
Ok(())
|
2023-09-19 08:52:12 +00:00
|
|
|
}
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
#[tokio::test]
|
|
|
|
async fn test_startup() -> Result<()> {
|
|
|
|
let db = DataBase::new("startup_test.db").await?;
|
|
|
|
|
|
|
|
db.register_devices(&Devices {
|
2023-09-22 05:43:56 +00:00
|
|
|
plugs: vec![("test".to_string(), true)],
|
2023-10-19 14:26:09 +00:00
|
|
|
thermostat: Vec::new(),
|
|
|
|
thermometer: Vec::new(),
|
2023-09-21 08:08:23 +00:00
|
|
|
})?;
|
|
|
|
|
|
|
|
fs::remove_file("startup_test.db")?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-19 09:18:22 +00:00
|
|
|
#[tokio::test]
|
|
|
|
async fn test_write() -> Result<()> {
|
|
|
|
let db = DataBase::new("write_test.db").await?;
|
|
|
|
|
2023-09-21 08:08:23 +00:00
|
|
|
let device_name = "test";
|
|
|
|
|
|
|
|
db.register_devices(&Devices {
|
2023-09-22 05:43:56 +00:00
|
|
|
plugs: vec![(device_name.to_string(), true)],
|
2023-10-19 14:26:09 +00:00
|
|
|
thermostat: Vec::new(),
|
|
|
|
thermometer: Vec::new(),
|
2023-09-21 08:08:23 +00:00
|
|
|
})?;
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
db.write(device_name, 0, "watts", 5.5)?;
|
2023-09-21 08:46:23 +00:00
|
|
|
|
|
|
|
let device_descriptor = "udo";
|
|
|
|
db.change_device_name(device_name, device_descriptor)?;
|
|
|
|
|
|
|
|
let devices = db.devices()?;
|
|
|
|
|
2023-10-10 12:06:26 +00:00
|
|
|
assert_eq!(devices.plugs[0].desc.as_ref().unwrap(), device_descriptor);
|
|
|
|
assert_eq!(devices.plugs[0].id, device_name);
|
2023-09-19 09:18:22 +00:00
|
|
|
|
|
|
|
fs::remove_file("write_test.db")?;
|
|
|
|
|
|
|
|
Ok(())
|
2023-09-19 08:52:12 +00:00
|
|
|
}
|
2023-10-23 08:03:16 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn action_set_test() -> Result<()> {
|
|
|
|
let db = DataBase::new("action_set_test.db").await?;
|
|
|
|
|
|
|
|
let thermometer = "shelly_plus_ht";
|
|
|
|
let thermostat = "shelly_trv";
|
|
|
|
|
|
|
|
db.register_devices(&Devices {
|
|
|
|
plugs: Vec::new(),
|
|
|
|
thermostat: vec![thermostat.to_string()],
|
|
|
|
thermometer: vec![thermometer.to_string()],
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let mut action_set = ActionSet::default();
|
|
|
|
action_set.chain(Action::new(thermometer, ActionType::Push, "temperature"));
|
|
|
|
action_set.chain(Action::new(thermostat, ActionType::Receive, "temperature"));
|
|
|
|
|
|
|
|
let action_id = db.insert_action_set(action_set.clone())?;
|
|
|
|
let cmp_action_set = db.action_set(action_id)?;
|
|
|
|
|
|
|
|
assert_eq!(action_set, cmp_action_set);
|
|
|
|
|
|
|
|
let action_sets_thermometer = db.action_sets(thermometer)?;
|
|
|
|
let action_sets_thermostat = db.action_sets(thermostat)?;
|
|
|
|
|
|
|
|
assert_eq!(action_sets_thermometer, action_sets_thermostat);
|
|
|
|
|
|
|
|
fs::remove_file("action_set_test.db")?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2023-09-19 08:52:12 +00:00
|
|
|
}
|