Compare commits

...

3 Commits

3 changed files with 38 additions and 13 deletions

View File

@ -5,7 +5,7 @@ Work in progress.
## Features and Todo ## Features and Todo
- Authn/z - Authn/z
- [x] Token authentication - [x] Authentication and token retrieval
- [ ] Persistence of tokens - [ ] Persistence of tokens
- Core functionality - Core functionality
- [x] Enumerate sites and chargers - [x] Enumerate sites and chargers
@ -13,9 +13,12 @@ Work in progress.
- [x] Read charger status - [x] Read charger status
- [ ] Control charging (start/pause/resume/stop) - [ ] Control charging (start/pause/resume/stop)
- [ ] Control dynamic current limits - [ ] Control dynamic current limits
- [ ] Websocket event stream - Event stream
- [x] Websocket connection (raw SignalR messages)
- [ ] Event decoding
- Ergonomics - Ergonomics
- [ ] Enums for protocol constants - [ ] Enums for protocol constants
- [ ] Proper SignalR support with Tokio

View File

@ -411,4 +411,27 @@ impl Charger {
pub fn latest_session(&self, ctx: &mut Context) -> Result<Option<ChargingSession>, ApiError> { pub fn latest_session(&self, ctx: &mut Context) -> Result<Option<ChargingSession>, ApiError> {
ctx.maybe_get(&format!("chargers/{}/sessions/latest", &self.id)) ctx.maybe_get(&format!("chargers/{}/sessions/latest", &self.id))
} }
fn command(&self, ctx: &mut Context, command: &str) -> Result<(), ApiError> {
ctx.post(&format!("chargers/{}/commands/{}", self.id, command), &())
}
pub fn start(&self, ctx: &mut Context) -> Result<(), ApiError> {
self.command(ctx, "start_charging")
}
pub fn pause(&self, ctx: &mut Context) -> Result<(), ApiError> {
self.command(ctx, "pause_charging")
}
pub fn resume(&self, ctx: &mut Context) -> Result<(), ApiError> {
self.command(ctx, "resume_charging")
}
pub fn stop(&self, ctx: &mut Context) -> Result<(), ApiError> {
self.command(ctx, "stop_charging")
}
} }

View File

@ -31,9 +31,6 @@ pub enum RecvError {
#[error("Bad message type")] #[error("Bad message type")]
BadMessageType, BadMessageType,
#[error("Not a SignalR message: {0:?}")]
NotSignalRMessage(String),
#[error("Invalid json: {0}")] #[error("Invalid json: {0}")]
InvalidJson(#[from] serde_json::Error), InvalidJson(#[from] serde_json::Error),
@ -41,7 +38,9 @@ pub enum RecvError {
TungsteniteError(#[from] tungstenite::Error), TungsteniteError(#[from] tungstenite::Error),
} }
pub struct Stream { sock: WebSocket<MaybeTlsStream<TcpStream>> } pub struct Stream {
sock: WebSocket<MaybeTlsStream<TcpStream>>,
}
impl Stream { impl Stream {
pub fn open(ctx: &mut Context) -> Result<Stream, NegotiateError> { pub fn open(ctx: &mut Context) -> Result<Stream, NegotiateError> {
@ -88,15 +87,15 @@ impl Stream {
self.sock.send(Message::Text(msg)) self.sock.send(Message::Text(msg))
} }
pub fn recv(&mut self) -> Result<serde_json::Value, RecvError> { pub fn recv(&mut self) -> Result<Vec<serde_json::Value>, RecvError> {
let msg = self.sock.read()?; let msg = self.sock.read()?;
let Message::Text(txt) = msg else { return Err(RecvError::BadMessageType) }; let Message::Text(txt) = msg else { return Err(RecvError::BadMessageType) };
let json: &str = match txt.strip_suffix("\x1E") {
None => return Err(RecvError::NotSignalRMessage(txt)), let msgs = txt.split_terminator('\x1E')
Some(json) => json .filter_map(|s| serde_json::from_str(s).ok())
}; .collect();
dbg!(&json);
Ok(serde_json::from_str(json)?) Ok(msgs)
} }
pub fn subscribe(&mut self, id: &str) -> Result<(), tungstenite::Error> { pub fn subscribe(&mut self, id: &str) -> Result<(), tungstenite::Error> {