List machines in rest api

This commit is contained in:
Oshgnacknak authored and Robin Krämer committed 2026-01-15 16:57:09 +01:00
1 parent 94bd29c734
commit 057afb0b2e
7 files changed
+175 -8

No files matched your search

+2 -2
View File
@@ -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
View File
@@ -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 {
+35
View File
@@ -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
View File
@@ -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;
+3 -1
View File
@@ -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
View File
@@ -1,3 +1,4 @@
pub mod handlers;
pub mod init;
pub mod util;
pub mod rest_api;
+107
View File
@@ -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))
}