add sensor values

This commit is contained in:
Romulus21
2024-12-06 23:58:13 +01:00
parent ba67b0becd
commit f12ab66d55
10 changed files with 199 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
deploy: deploy:
npx tailwindcss -i ./input.css -o ./style/output.css npx tailwindcss -i ./input.css -o ./style/output.css --minify
tac Cargo.toml | sed '1s/^.//' | tac > fichier_temp.txt && mv fichier_temp.txt Cargo.toml tac Cargo.toml | sed '1s/^.//' | tac > fichier_temp.txt && mv fichier_temp.txt Cargo.toml
#cargo leptos build #cargo leptos build
cargo leptos build --release cargo leptos build --release

1
rustfmt.toml Normal file
View File

@@ -0,0 +1 @@
edition = "2021"

View File

@@ -21,6 +21,7 @@ pub fn App() -> impl IntoView {
<Route path="/" view=move || view! { <Home/> }/> <Route path="/" view=move || view! { <Home/> }/>
<Route path="/liens" view=move || view! { <Links/> }/> <Route path="/liens" view=move || view! { <Links/> }/>
<Route path="/formulaire" view=move || view! { <FormValues/> }/> <Route path="/formulaire" view=move || view! { <FormValues/> }/>
<Route path="/donnees" view=move || view! { <Data/> }/>
//<Route path="/*any" view=move || view! { <NotFound/> }/> //<Route path="/*any" view=move || view! { <NotFound/> }/>
</Routes> </Routes>
</main> </main>
@@ -45,6 +46,9 @@ pub fn Navigation() -> impl IntoView {
<a href="/formulaire" <a href="/formulaire"
class="hover:text-third hover:border-b border-third inline-block transition-colors" class="hover:text-third hover:border-b border-third inline-block transition-colors"
class:active-link=move || location.pathname.get() == "/formulaire">Formulaire</a> class:active-link=move || location.pathname.get() == "/formulaire">Formulaire</a>
<a href="/donnees"
class="hover:text-third hover:border-b border-third inline-block transition-colors"
class:active-link=move || location.pathname.get() == "/donnees">Données</a>
</nav> </nav>
} }
} }

View File

@@ -42,11 +42,12 @@ pub const OPTIONS: &[Option] = &[
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Value { pub struct Value {
id: u16, id: i32,
service: String, service: String,
capteur: String, capteur: String,
type_donnee: String, type_donnee: String,
donnee: String, pub donnee: String,
pub date_donnee: String,
} }
impl Value { impl Value {
@@ -71,6 +72,46 @@ impl Value {
.execute(crate::database::get_db()) .execute(crate::database::get_db())
.await .await
} }
#[cfg(feature = "ssr")]
pub async fn get_one(topic: String) -> Result<Self, sqlx::Error> {
let split: Vec<&str> = topic.split("/").collect();
let unknow_value = Value {
id: 0,
service: "".to_string(),
capteur: "".to_string(),
type_donnee: "".to_string(),
donnee: "--".to_string(),
date_donnee: "--:--".to_string(),
};
if split.len() == 3 {
let res = sqlx::query!(
"SELECT * FROM donnees WHERE service = ? AND capteur = ? AND type = ?",
split[0],
split[1],
split[2],
//chrono::Local::now().naive_local(),
)
.map(|x| Self {
id: x.id,
service: x.service,
capteur: x.capteur,
type_donnee: x.r#type,
donnee: x.donnee,
date_donnee: x.date_donnee.format("%H:%M").to_string(),
})
.fetch_one(crate::database::get_db())
.await;
match res {
Ok(res) => Ok(res),
Err(_) => Ok(unknow_value)
}
} else {
Ok(unknow_value)
}
}
} }
fn find_option(value: &str) -> Result<&Option, &str> { fn find_option(value: &str) -> Result<&Option, &str> {

94
src/routes/data.rs Normal file
View File

@@ -0,0 +1,94 @@
use leptos::*;
use leptos_meta::*;
use crate::models::Value;
#[component]
pub fn Data() -> impl IntoView {
view! {
<Title text="Capteurs"/>
<ul class="flex gap-5 flex-wrap m-5">
<ValueCard location="Bureau".to_string()
sensor="Température".to_string()
unity="°C".to_string()
color="text-third".to_string()
topic="maison/bureau/temperature".to_string() />
<ValueCard location="Bureau".to_string()
sensor="CO2".to_string()
unity="ppm".to_string()
color="text-green".to_string()
topic="maison/bureau/co2".to_string() />
<ValueCard location="Bureau".to_string()
sensor="Pression".to_string()
unity="hPa".to_string()
color="text-fourth".to_string()
topic="maison/bureau/pression".to_string() />
<ValueCard location="Extérieur".to_string()
sensor="Température".to_string()
unity="°C".to_string()
color="text-third".to_string()
topic="meteo/exterieur/temperature".to_string() />
<ValueCard location="Véranda".to_string()
sensor="Température".to_string()
unity="°C".to_string()
color="text-third".to_string()
topic="meteo/veranda/temperature".to_string() />
</ul>
}
}
#[server(ValueAction, "/api")]
pub async fn get_value(topic: String) -> Result<crate::models::Value, ServerFnError> {
crate::models::Value::get_one(topic).await.map_err(|x| {
let err = format!("Error while posting a comment: {x:?}");
tracing::error!("{err}");
ServerFnError::ServerError("Could not post a comment, try again later".into())
})
}
#[component]
pub fn ValueCard(topic: String, location: String, sensor: String, unity: String, color: String) -> impl IntoView {
let (sensor_props, _) = create_signal((location, sensor, unity, color));
let value = create_resource(
move || topic.clone(),
|topic| async { get_value(topic).await },
);
view! {
<li class="flex p-3 w-80 bg-prim-light rounded-lg justify-between">
<Suspense fallback=move || view! { <p>"Loading Value"</p> }>
<ErrorBoundary fallback=|_| {
view! { <p class="error-messages text-xs-center">"Something went wrong, please try again later."</p>}
}>
{move || {
value.get().map(move |x| {
x.map(move |result| {
view! {
<Card sensor_props value=result />
}
})
})
}}
</ErrorBoundary>
</Suspense>
</li>
}
}
#[component]
pub fn Card(sensor_props: ReadSignal<(String, String, String, String)>, value: Value) -> impl IntoView {
let (location, sensor, unity, color) = sensor_props.get();
view! {
<div class="flex flex-col">
<div class="text-xl flex-1">{location}</div>
<div class="text-second-dark">{sensor}</div>
<div class="text-second-dark text-sm">{value.date_donnee}</div>
</div>
<h2 class="text-4xl flex ml-5 -my-2 text-center {color}">
<strong>{value.donnee}</strong>
<span class="text-2xl mt-5">{unity}</span>
</h2>
}
}

View File

@@ -1,5 +1,5 @@
use leptos::*; use leptos::*;
//use leptos_meta::*; use leptos_meta::*;
use leptos_router::*; use leptos_router::*;
#[server(GetLinksAction, "/api", "GetJson")] #[server(GetLinksAction, "/api", "GetJson")]
@@ -70,6 +70,7 @@ pub fn Links() -> impl IntoView {
}; };
view! { view! {
<Title text="Liens"/>
<ul class="flex flex-wrap gap-5 m-5 justify-center"> <ul class="flex flex-wrap gap-5 m-5 justify-center">
<Suspense fallback=move || view! {<p>"Loading Comments from the article"</p> }> <Suspense fallback=move || view! {<p>"Loading Comments from the article"</p> }>
<ErrorBoundary fallback=|_| { <ErrorBoundary fallback=|_| {

View File

@@ -1,5 +1,7 @@
mod data;
mod link; mod link;
mod value; mod value;
pub use data::*;
pub use link::*; pub use link::*;
pub use value::*; pub use value::*;

View File

@@ -1,5 +1,5 @@
use leptos::*; use leptos::*;
//use leptos_meta::*; use leptos_meta::*;
use leptos_router::*; use leptos_router::*;
use crate::models::OPTIONS; use crate::models::OPTIONS;
@@ -29,6 +29,8 @@ pub fn FormValues() -> impl IntoView {
); );
view! { view! {
<Title text="Formulaire"/>
<div class="my-5 mx-auto w-72 p-6 bg-prim-light rounded-lg"> <div class="my-5 mx-auto w-72 p-6 bg-prim-light rounded-lg">
<h2 class="pb-6 text-2xl text-center">"Formulaire"</h2> <h2 class="pb-6 text-2xl text-center">"Formulaire"</h2>

View File

@@ -556,6 +556,16 @@ video {
margin: 1.25rem; margin: 1.25rem;
} }
.-my-2 {
margin-top: -0.5rem;
margin-bottom: -0.5rem;
}
.mx-5 {
margin-left: 1.25rem;
margin-right: 1.25rem;
}
.mx-auto { .mx-auto {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@@ -575,6 +585,10 @@ video {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
.ml-5 {
margin-left: 1.25rem;
}
.mt-3 { .mt-3 {
margin-top: 0.75rem; margin-top: 0.75rem;
} }
@@ -615,6 +629,10 @@ video {
width: 18rem; width: 18rem;
} }
.w-80 {
width: 20rem;
}
.min-w-60 { .min-w-60 {
min-width: 15rem; min-width: 15rem;
} }
@@ -668,6 +686,10 @@ video {
border-width: 1px; border-width: 1px;
} }
.border-b {
border-bottom-width: 1px;
}
.border-third { .border-third {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(252 68 61 / var(--tw-border-opacity)); border-color: rgb(252 68 61 / var(--tw-border-opacity));
@@ -692,6 +714,10 @@ video {
background-color: rgb(252 68 61 / var(--tw-bg-opacity)); background-color: rgb(252 68 61 / var(--tw-bg-opacity));
} }
.p-3 {
padding: 0.75rem;
}
.p-6 { .p-6 {
padding: 1.5rem; padding: 1.5rem;
} }
@@ -739,11 +765,20 @@ video {
line-height: 2rem; line-height: 2rem;
} }
.text-\[4rem\] {
font-size: 4rem;
}
.text-lg { .text-lg {
font-size: 1.125rem; font-size: 1.125rem;
line-height: 1.75rem; line-height: 1.75rem;
} }
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-xl { .text-xl {
font-size: 1.25rem; font-size: 1.25rem;
line-height: 1.75rem; line-height: 1.75rem;
@@ -754,6 +789,11 @@ video {
color: rgb(146 148 150 / var(--tw-text-opacity)); color: rgb(146 148 150 / var(--tw-text-opacity));
} }
.text-third {
--tw-text-opacity: 1;
color: rgb(252 68 61 / var(--tw-text-opacity));
}
.transition-colors { .transition-colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -770,6 +810,11 @@ video {
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.hover\:border-third:hover {
--tw-border-opacity: 1;
border-color: rgb(252 68 61 / var(--tw-border-opacity));
}
.hover\:bg-prim-lightest:hover { .hover\:bg-prim-lightest:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(46 50 53 / var(--tw-bg-opacity)); background-color: rgb(46 50 53 / var(--tw-bg-opacity));

View File

@@ -23,6 +23,10 @@ module.exports = {
light: "#FFD885", light: "#FFD885",
DEFAULT: "#FEBB2E", DEFAULT: "#FEBB2E",
}, },
green: "#00DA00",
},
fontSize: {
"4xl": ["4rem", "1"],
}, },
}, },
}, },