Skip to content

Commit

Permalink
relay interface and voxpower inhibiter skeleton (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas-D20 authored May 2, 2024
1 parent 534aca2 commit 08bf82b
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/builtin_devices/panduza/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::device::Factory as DeviceFactory;

mod fake;
mod server;
mod voxpower_inhibiter;



Expand All @@ -10,6 +11,7 @@ pub fn import_plugin_producers(factory: &mut DeviceFactory)


factory.add_producer("panduza.server", Box::new(server::DeviceProducer{}));
factory.add_producer("panduza.voxpower_inhibiter", Box::new(voxpower_inhibiter::DeviceProducer{}));

fake::import_plugin_producers(factory);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use async_trait::async_trait;
use crate::platform::PlatformError;
use crate::meta::relay;
use crate::interface::AmInterface;
use crate::interface::builder::Builder as InterfaceBuilder;

use crate::connector::serial::tty;



/// Voxpower Inhibiter Channel Data
///
struct VoxpowerInhibiterActions {
state_open: String,
}

#[async_trait]
impl relay::RelayActions for VoxpowerInhibiterActions {

/// Initialize the interface
///
async fn initializating(&mut self, interface: &AmInterface) -> Result<(), PlatformError> {
// let self.channel = channel;

// tty::Get(name)

return Ok(());
}

/// Configuration of the interface
///
async fn config(&mut self, interface: &AmInterface) -> Result<(), PlatformError> {
return Ok(());
}

/// Read the enable value
///
async fn read_state_open(&mut self, interface: &AmInterface) -> Result<bool, PlatformError> {
interface.lock().await.log_info(
format!("VoxpowerInhibiter - read_state_open {}", self.state_open)
);
if self.state_open == "H" {
return Ok(true);
} else {
return Ok(false);
}
}

/// Write the enable value
async fn write_state_open(&mut self, interface: &AmInterface, v: bool) {
if v {
let command = "I\n"; //format!("I{}\n", self.channel);
self.state_open = command.to_string();
interface.lock().await.log_info(
format!("VoxpowerInhibiter - inhibit channel: {}", self.state_open)
);
} else {
let command = "E\n"; //format!("E{}\n", self.channel);
self.state_open = command.to_string();
interface.lock().await.log_info(
format!("VoxpowerInhibiter - enable channel: {}", self.state_open)
);
}
}
}


/// Interface to emulate a Bench Power Channel
///
pub fn build<A: Into<String>>(
name: A,
) -> InterfaceBuilder {

return relay::build(
name,
Box::new(VoxpowerInhibiterActions {
state_open: "L".to_string(),
})
)
}
54 changes: 54 additions & 0 deletions src/builtin_devices/panduza/voxpower_inhibiter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use async_trait::async_trait;
use tokio::time::{sleep, Duration};

use crate::platform::PlatformError;
use crate::subscription;
use crate::interface::{self, Runner};
use crate::interface::AmInterface;
use crate::interface::AmRunner;
use crate::device::{ Device, traits::DeviceActions, traits::Producer };

use crate::interface::builder::Builder as InterfaceBuilder;
struct PlatformInterfaceSubscriber;


mod itf_voxpower_inhibiter;


struct VoxpowerInhibiter;


impl DeviceActions for VoxpowerInhibiter {

// fn hunt(&self) -> LinkedList<Value> {
// return LinkedList::new();
// }

/// Create the interfaces
fn interface_builders(&self, device_settings: &serde_json::Value)
-> Result<Vec<InterfaceBuilder>, PlatformError>
{
let mut list = Vec::new();
for n in 2..10 {
list.push(
itf_voxpower_inhibiter::build(format!("channel_{}", n))
);
}

return Ok(list);
}
}




pub struct DeviceProducer;

impl Producer for DeviceProducer {

fn produce(&self) -> Result<Box<dyn DeviceActions>, PlatformError> {
return Ok(Box::new(VoxpowerInhibiter{}));
}

}

1 change: 1 addition & 0 deletions src/meta/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod bpc;
pub mod relay;

240 changes: 240 additions & 0 deletions src/meta/relay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
use std::sync::Arc;

use async_trait::async_trait;
use serde_json::Value;
use tokio::sync::Mutex;

use crate::attribute::{self, JsonAttribute};
use crate::interface::AmInterface;
use crate::platform::PlatformError;
use crate::{interface, subscription};
use crate::interface::builder::Builder as InterfaceBuilder;


#[async_trait]
pub trait RelayActions: Send + Sync {

/// Initialize the interface
/// The connector initialization must be done here
///
async fn initializating(&mut self, interface: &AmInterface) -> Result<(), PlatformError>;

async fn config(&mut self, interface: &AmInterface) -> Result<(), PlatformError>;

async fn read_state_open(&mut self, interface: &AmInterface) -> Result<bool, PlatformError>;

async fn write_state_open(&mut self, interface: &AmInterface, v: bool);
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


pub struct StateAttribute {
attr: JsonAttribute,
}


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

struct RelayInterface {

actions: Box<dyn RelayActions>
}
type AmRelayInterface = Arc<Mutex<RelayInterface>>;

impl RelayInterface {
fn new(actions: Box<dyn RelayActions>) -> RelayInterface {
return RelayInterface {
actions: actions
}
}
fn new_am(actions: Box<dyn RelayActions>) -> AmRelayInterface {
return Arc::new(Mutex::new( RelayInterface::new(actions) ));
}
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

struct RelayStates {
relay_interface: Arc<Mutex<RelayInterface>>
}


#[async_trait]
impl interface::fsm::States for RelayStates {

/// Just wait for an fsm event for the connection
///
async fn connecting(&self, interface: &AmInterface)
{
interface::basic::wait_for_fsm_event(interface).await;
}

/// Initialize the interface
///
async fn initializating(&self, interface: &AmInterface)
{
// Custom initialization slot
self.relay_interface.lock().await.actions.initializating(&interface).await.unwrap();

// Register attributes
interface.lock().await.register_attribute(JsonAttribute::new_boxed("state", true));

// Init state
let state_value = self.relay_interface.lock().await.actions.read_state_open(&interface).await.unwrap();
interface.lock().await.update_attribute_with_bool("state", "value", state_value);

// Publish all attributes for start
interface.lock().await.publish_all_attributes().await;

// Notify the end of the initialization
interface.lock().await.set_event_init_done();
}

async fn running(&self, interface: &AmInterface)
{
println!("running");


interface::basic::wait_for_fsm_event(interface).await;
}

async fn error(&self, interface: &AmInterface)
{
println!("error");
}

async fn cleaning(&self, interface: &AmInterface)
{
println!("cleaning");
}
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

const ID_STATE: subscription::Id = 0;

struct RelaySubscriber {
relay_interface: Arc<Mutex<RelayInterface>>
}

impl RelaySubscriber {

///
///
#[inline(always)]
async fn process_state_open(&self, interface: &AmInterface, attribute_name: &str, field_name: &str, field_data: &Value) {
let requested_value = field_data.as_bool().unwrap();
self.relay_interface.lock().await
.actions.write_state_open(&interface, requested_value).await;

let r_value = self.relay_interface.lock().await
.actions.read_state_open(&interface).await
.unwrap();

interface.lock().await
.update_attribute_with_bool("state", "value", r_value);
}
}

#[async_trait]
impl interface::subscriber::Subscriber for RelaySubscriber {

/// Get the list of attributes names
///
async fn attributes_names(&self) -> Vec<(subscription::Id, String)> {
return vec![
(ID_STATE, "state".to_string())
];
}




/// Process a message
///
async fn process(&self, interface: &AmInterface, msg: &subscription::Message) {
// Common processing
interface::basic::process(&interface, msg).await;

match msg {
subscription::Message::Mqtt(msg) => {
match msg.id() {
subscription::ID_PZA_CMDS_SET => {
// interface.lock().await.publish_info().await;

// only when running state

println!("RelaySubscriber::process: {:?}", msg.topic());
println!("RelaySubscriber::process: {:?}", msg.payload());

let payload = msg.payload();
let oo = serde_json::from_slice::<Value>(payload).unwrap();
let o = oo.as_object().unwrap();


for (attribute_name, fields) in o.iter() {
for (field_name, field_data) in fields.as_object().unwrap().iter() {
if attribute_name == "state" && field_name == "value" {
self.process_state_open(&interface, attribute_name, field_name, field_data).await;
}
}
}
interface.lock().await.publish_all_attributes().await;


},
_ => {
// not managed by the common level
}
}
}
_ => {
// not managed by the common level
}
}
}


}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

/// Build the meta interface for a Voxpower Channel
///
pub fn build<A: Into<String>>(
name: A,
actions: Box<dyn RelayActions>
) -> InterfaceBuilder {

let c = RelayInterface::new_am(actions);

return InterfaceBuilder::new(
name,
"relay",
"0.0",
Box::new(RelayStates{relay_interface: c.clone()}),
Box::new(RelaySubscriber{relay_interface: c.clone()})
);
}

0 comments on commit 08bf82b

Please sign in to comment.