List machines in rest api
This commit is contained in:
1 parent
94bd29c734
commit
057afb0b2e
7 files changed
+175
-8
No files matched your search
@@ -41,7 +41,6 @@ impl MachineAct for LaserMachine {
|
||||
}
|
||||
|
||||
fn act_machine_message(&mut self, msg: MachineMessage) {
|
||||
tracing::info!("{:?}", msg);
|
||||
match msg {
|
||||
MachineMessage::SubscribeNamespace(namespace) => {
|
||||
self.namespace.namespace = Some(namespace);
|
||||
@@ -69,7 +68,8 @@ impl MachineAct for LaserMachine {
|
||||
/*Doesnt connect to any Machine so do nothing*/
|
||||
{
|
||||
()
|
||||
}
|
||||
},
|
||||
MachineMessage::RequestValues(sender) => sender.send_blocking(crate::MachineValues { state: serde_json::Value::Null, live_values: serde_json::Value::Null })
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -13,9 +13,8 @@ use machine_identification::{
|
||||
use serde::Serialize;
|
||||
use smol::channel::{Receiver, Sender};
|
||||
use socketioxide::extract::SocketRef;
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
use std::{any::Any, sync::Arc, time::Instant};
|
||||
pub mod analog_input_test_machine;
|
||||
pub mod aquapath1;
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
pub mod buffer1;
|
||||
@@ -36,7 +35,6 @@ pub const MACHINE_WINDER_V1: u16 = 0x0002;
|
||||
pub const MACHINE_EXTRUDER_V1: u16 = 0x0004;
|
||||
pub const MACHINE_LASER_V1: u16 = 0x0006;
|
||||
pub const MACHINE_MOCK: u16 = 0x0007;
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
pub const MACHINE_BUFFER_V1: u16 = 0x0008;
|
||||
pub const MACHINE_AQUAPATH_V1: u16 = 0x0009;
|
||||
pub const MACHINE_WAGO_POWER_V1: u16 = 0x000A;
|
||||
@@ -276,6 +274,12 @@ pub trait MachineAct {
|
||||
fn act(&mut self, now: Instant);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct MachineValues {
|
||||
pub state: serde_json::Value,
|
||||
pub live_values: serde_json::Value,
|
||||
}
|
||||
|
||||
// generic MachineMessage allows us to implement actions
|
||||
// to manage or mutate machines with simple messages sent to the Recv Channel of the given Machine,
|
||||
// which the machine itself will handle to avoid locking
|
||||
@@ -287,6 +291,7 @@ pub enum MachineMessage {
|
||||
HttpApiJsonRequest(serde_json::Value),
|
||||
ConnectToMachine(MachineConnection),
|
||||
DisconnectMachine(MachineConnection),
|
||||
RequestValues(Sender<MachineValues>),
|
||||
}
|
||||
|
||||
pub trait MachineApi {
|
||||
|
||||
@@ -41,6 +41,29 @@ impl MachineIdentification {
|
||||
pub const fn is_valid(&self) -> bool {
|
||||
self.vendor != 0 && self.machine != 0
|
||||
}
|
||||
|
||||
pub fn vendor_str(&self) -> String {
|
||||
match self.vendor {
|
||||
x if x == VENDOR_QITECH => "QiTech".to_string(),
|
||||
_ => "N/A".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slug(&self) -> String {
|
||||
match self.machine {
|
||||
x if x == MACHINE_WINDER_V1 => "winder_v1".to_string(),
|
||||
x if x == MACHINE_EXTRUDER_V1 => "extruder_v1".to_string(),
|
||||
x if x == MACHINE_LASER_V1 => "laser_v1".to_string(),
|
||||
x if x == MACHINE_MOCK => "mock".to_string(),
|
||||
x if x == MACHINE_AQUAPATH_V1 => "aquapath_v1".to_string(),
|
||||
x if x == MACHINE_BUFFER_V1 => "buffer_v1".to_string(),
|
||||
x if x == MACHINE_EXTRUDER_V2 => "extruder_v2".to_string(),
|
||||
x if x == TEST_MACHINE => "test_machine".to_string(),
|
||||
x if x == IP20_TEST_MACHINE => "ip20_test_machine".to_string(),
|
||||
x if x == ANALOG_INPUT_TEST_MACHINE => "analog_input_test_machine".to_string(),
|
||||
_ => "N/A".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@@ -149,6 +172,18 @@ use ethercat_hal::helpers::ethercrab_types::{
|
||||
use ethercrab::MainDevice;
|
||||
use ethercrab::SubDeviceIdentity;
|
||||
|
||||
use crate::ANALOG_INPUT_TEST_MACHINE;
|
||||
use crate::IP20_TEST_MACHINE;
|
||||
use crate::MACHINE_AQUAPATH_V1;
|
||||
use crate::MACHINE_BUFFER_V1;
|
||||
use crate::MACHINE_EXTRUDER_V1;
|
||||
use crate::MACHINE_EXTRUDER_V2;
|
||||
use crate::MACHINE_LASER_V1;
|
||||
use crate::MACHINE_MOCK;
|
||||
use crate::MACHINE_WINDER_V1;
|
||||
use crate::TEST_MACHINE;
|
||||
use crate::VENDOR_QITECH;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MachineIdentificationAddresses {
|
||||
pub vendor_word: u16,
|
||||
|
||||
+19
-2
@@ -3,11 +3,12 @@ use crate::rest::handlers::write_machine_device_identification::MachineDeviceInf
|
||||
use crate::socketio::main_namespace::MainNamespaceEvents;
|
||||
use crate::socketio::main_namespace::machines_event::{MachineObj, MachinesEventBuilder};
|
||||
use crate::socketio::namespaces::Namespaces;
|
||||
use anyhow::{Result, bail};
|
||||
use control_core::socketio::event::GenericEvent;
|
||||
use ethercat_hal::devices::EthercatDevice;
|
||||
use ethercrab::SubDeviceRef;
|
||||
use ethercrab::{MainDevice, SubDeviceGroup, subdevice_group::Op};
|
||||
use machines::machine_identification::{DeviceIdentification, MachineIdentificationUnique};
|
||||
use machines::machine_identification::{self, DeviceIdentification, MachineIdentificationUnique};
|
||||
use machines::serial::registry::SERIAL_DEVICE_REGISTRY;
|
||||
use machines::{Machine, MachineMessage};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -123,11 +124,27 @@ impl EthercatSetup {
|
||||
|
||||
impl SharedState {
|
||||
pub async fn send_machines_event(&self) {
|
||||
let event = MachinesEventBuilder().build(self.current_machines_meta.lock().await.clone());
|
||||
let event = MachinesEventBuilder().build(self.get_machines_meta().await);
|
||||
let main_namespace = &mut self.socketio_setup.namespaces.write().await.main_namespace;
|
||||
main_namespace.emit(MainNamespaceEvents::MachinesEvent(event));
|
||||
}
|
||||
|
||||
pub async fn get_machines_meta(&self) -> Vec<MachineObj> {
|
||||
self.current_machines_meta.lock().await.clone()
|
||||
}
|
||||
|
||||
pub async fn message_machine(&self, machine_identification_unique: MachineIdentificationUnique, message: MachineMessage) -> Result<()> {
|
||||
let machines = self.api_machines.lock().await;
|
||||
let sender = machines.get(&machine_identification_unique);
|
||||
|
||||
if let Some(sender) = sender {
|
||||
sender.send(message).await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
bail!("Unknown machine!")
|
||||
}
|
||||
|
||||
/// Removes a machine by its unique identifier
|
||||
pub async fn remove_machine(&self, machine_id: &MachineIdentificationUnique) {
|
||||
let mut current_machines = self.current_machines_meta.lock().await;
|
||||
|
||||
@@ -9,6 +9,7 @@ use tracing::Level;
|
||||
use super::handlers::machine_mutation::post_machine_mutate;
|
||||
use super::handlers::write_machine_device_identification::post_write_machine_device_identification;
|
||||
use crate::app_state::SharedState;
|
||||
use crate::rest::rest_api::rest_api_router;
|
||||
use crate::socketio::init::init_socketio;
|
||||
|
||||
use crate::rest::handlers::metrics::metrics_router;
|
||||
@@ -29,6 +30,7 @@ async fn init_api(app_state: Arc<SharedState>) -> Result<()> {
|
||||
)
|
||||
.route("/api/v1/machine/mutate", post(post_machine_mutate))
|
||||
.nest("/api/v1/metrics", metrics_router())
|
||||
.nest("/api/v2", rest_api_router())
|
||||
.layer(socketio_layer)
|
||||
.layer(cors)
|
||||
.layer(trace_layer)
|
||||
@@ -53,7 +55,7 @@ pub fn start_api_thread(app_state: Arc<SharedState>) -> std::thread::JoinHandle<
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
|
||||
if let Err(err) = rt.block_on(init_api(app_state.clone())) {
|
||||
if let Err(err) = rt.block_on(init_api(app_state)) {
|
||||
eprintln!("API server exited with error: {err:?}");
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod handlers;
|
||||
pub mod init;
|
||||
pub mod util;
|
||||
pub mod rest_api;
|
||||
@@ -0,0 +1,107 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{Router, debug_handler, Json};
|
||||
use axum::extract::{Path, State};
|
||||
use axum::routing::get;
|
||||
use machines::MachineMessage;
|
||||
use machines::machine_identification::MachineIdentificationUnique;
|
||||
use machines::winder2::Winder2;
|
||||
use machines::winder2::api::{LiveValuesEvent, StateEvent, Winder2Events};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::app_state::SharedState;
|
||||
use crate::rest::util::ResponseUtil;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||
struct MachineResponce {
|
||||
legacy_id: MachineIdentificationUnique,
|
||||
serial: u16,
|
||||
vendor: String,
|
||||
slug: String,
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
impl From<MachineIdentificationUnique> for MachineResponce {
|
||||
|
||||
fn from(machine_identification_unique: MachineIdentificationUnique) -> Self {
|
||||
let vendor = machine_identification_unique.machine_identification.vendor_str();
|
||||
let slug = machine_identification_unique.machine_identification.slug();
|
||||
let serial = machine_identification_unique.serial;
|
||||
|
||||
MachineResponce {
|
||||
legacy_id: machine_identification_unique,
|
||||
serial,
|
||||
vendor,
|
||||
slug,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||
struct GetMachinesResponce {
|
||||
machines: Vec<MachineResponce>
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
async fn get_machines_handler(
|
||||
State(shared_state): State<Arc<SharedState>>,
|
||||
) -> Json<GetMachinesResponce> {
|
||||
|
||||
let machines = shared_state.get_machines_meta().await.into_iter().map(|m| {
|
||||
let vendor = m.machine_identification_unique.machine_identification.vendor_str();
|
||||
let slug = m.machine_identification_unique.machine_identification.slug();
|
||||
let serial = m.machine_identification_unique.serial;
|
||||
|
||||
MachineResponce {
|
||||
legacy_id: m.machine_identification_unique,
|
||||
serial,
|
||||
vendor,
|
||||
slug,
|
||||
error: m.error,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Json(GetMachinesResponce {
|
||||
machines
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||
struct GetMachineResponce {
|
||||
machine: MachineResponce,
|
||||
state: serde_json::Value,
|
||||
live_values: serde_json::Value,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
async fn get_winder_v1_handler(
|
||||
Path(serial): Path<u16>,
|
||||
State(shared_state): State<Arc<SharedState>>,
|
||||
) -> Json<GetMachinesResponce> {
|
||||
|
||||
let id = MachineIdentificationUnique {
|
||||
machine_identification: Winder2::MACHINE_IDENTIFICATION,
|
||||
serial,
|
||||
};
|
||||
|
||||
let (sender, receiver) = smol::channel::unbounded();
|
||||
shared_state.message_machine(machine_identification_unique, MachineMessage::RequestValues(sender)).await?;
|
||||
|
||||
if let Ok(values) = receiver.recv().await {
|
||||
return Json(GetMachineResponce {
|
||||
machine: MachineResponce::from(id),
|
||||
state: values.state,
|
||||
live_values: values.live_values,
|
||||
});
|
||||
}
|
||||
|
||||
bail!("Could not get values from machine")
|
||||
}
|
||||
|
||||
pub fn rest_api_router() -> Router<Arc<SharedState>> {
|
||||
Router::new()
|
||||
.route("/machine", get(get_machines_handler))
|
||||
.route("/machine/winder_v1/{serial}", get(get_winder_v1_handler))
|
||||
}
|
||||
Reference in new issue
Block a user