1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
//! ZWave basic functionality - top layer
//!
//! This is the top layer which handles the whole ZWave interface
//! and allows to easy access all nodes and their functionality.
//!
//! It's proposed to use this module from the crate.

//! The `Controller` provides the functionality to connected
//! to a Z-Wave network, to send  messages and to receive them.

pub use cmds::powerlevel::PowerLevelOperationStatus;
pub use cmds::powerlevel::PowerLevelStatus;
pub use cmds::MeterData;

use cmds::basic::Basic;
use cmds::info::NodeInfo;
use cmds::meter::Meter;
use cmds::powerlevel::PowerLevel;
use cmds::switch_binary::SwitchBinary;
use cmds::CommandClass;
use driver::serial::SerialMsg;
use driver::{Driver, GenericType};
use error::Error;

use std::cell::RefCell;
use std::clone::Clone;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::{thread, time};

pub trait Handler: Send {
    fn handle(self, msg: SerialMsg);
}

#[derive(Debug, Clone)]
pub struct Controller<D>
where
    D: Driver,
{
    driver: Arc<Mutex<D>>,
    nodes: Rc<RefCell<Vec<Node<D>>>>,
}

impl<D> Controller<D>
where
    D: Driver + Send + 'static,
{
    /// Generate a new Controller to interface with the z-wave network.
    pub fn new(driver: D) -> Result<Controller<D>, Error> {
        let controller = Controller {
            driver: Arc::new(Mutex::new(driver)),
            nodes: Rc::new(RefCell::new(vec![])),
        };

        controller.discover_nodes()?;

        Ok(controller)
    }

    /// Discover all nodes which are present in the network
    pub fn discover_nodes(&self) -> Result<(), Error> {
        // clear the existing nodes
        self.nodes.borrow_mut().clear();

        // get all node id's which are in the network
        let ids = self.driver.lock().unwrap().get_node_ids()?;

        // create a node object for each id
        for i in ids {
            // create the node for the given id
            self.nodes
                .borrow_mut()
                .push(Node::new(self.driver.clone(), i as u8));
        }

        // when everything went well, return no error
        Ok(())
    }
    /// This function returns the defined node and a mutable reference
    /// to the z-wave driver.
    pub fn node<I>(&mut self, id: I) -> Option<Node<D>>
    where
        I: Into<u8>,
    {
        let id = id.into();

        // loop over all nodes and check if the id exist
        for n in self.nodes.borrow().iter() {
            if id == n.get_id() {
                // return the node with the id
                return Some(n.clone());
            }
        }

        // when no id was found return nothing
        None
    }

    /// Return all node ids
    pub fn nodes(&self) -> Vec<u8> {
        // get all node ids
        self.nodes
            .borrow()
            .iter()
            .map(|n| n.id)
            .collect::<Vec<u8>>()
    }

    pub fn handle_messages(&self, h: Box<Fn(SerialMsg) + Send>) {
        let driver = self.driver.clone();
        let duration = time::Duration::from_millis(50);

        thread::spawn(move || loop {
            {
                let mut m_driver = driver.lock().unwrap();

                loop {
                    match m_driver.read() {
                        Ok(msg) => h(msg),
                        Err(_) => break,
                    }
                }
            }

            thread::sleep(duration);
        });
    }
}

/************************** Node Area *********************/

#[derive(Debug)]
pub struct Node<D>
where
    D: Driver,
{
    driver: Arc<Mutex<D>>,
    id: u8,
    types: Vec<GenericType>,
    cmds: Vec<CommandClass>,
}

impl<D> Node<D>
where
    D: Driver,
{
    // Create a new node.
    pub fn new(driver: Arc<Mutex<D>>, id: u8) -> Node<D> {
        let mut node = Node {
            driver: driver,
            id: id,
            types: vec![],
            cmds: vec![],
        };

        // update the node information
        node.update_node_info().is_ok();

        node
    }

    /// Updates the information of the node
    pub fn update_node_info(&mut self) -> Result<(), Error> {
        // convert it
        let (types, cmds) = self.node_info_get()?;

        self.types = types;
        self.cmds = cmds;

        Ok(())
    }

    // get the node id
    pub fn get_id(&self) -> u8 {
        self.id
    }

    pub fn get_commands(&self) -> Vec<CommandClass> {
        self.cmds.clone()
    }

    /// This function returns the GenericType for the node and the CommandClass.
    pub fn node_info_get(&self) -> Result<(Vec<GenericType>, Vec<CommandClass>), Error> {
        let mut driver = self.driver.lock().unwrap();

        // Send the command
        driver.write(NodeInfo::get(self.id))?;

        // Receive the result
        let msg = driver.read()?;

        // convert and return it
        NodeInfo::report(msg.data)
    }

    /// This function sets the basic status of the node.
    pub fn basic_set<V>(&self, value: V) -> Result<u8, Error>
    where
        V: Into<u8>,
    {
        // Send the command
        self.driver
            .lock()
            .unwrap()
            .write(Basic::set(self.id, value.into()))
    }

    pub fn basic_get(&self) -> Result<u8, Error> {
        let mut driver = self.driver.lock().unwrap();
        // Send the command
        driver.write(Basic::get(self.id))?;
        // read the answer and convert it
        match driver.read() {
            Ok(msg) => Basic::report(msg.data),
            Err(err) => Err(err),
        }
    }

    /// The Binary Switch Command Class is used to control devices with On/Off
    /// or Enable/Disable capability.
    ///
    /// The Binary Switch Set command, version 1 is used to set a binary value.
    pub fn switch_binary_set<V>(&self, value: V) -> Result<u8, Error>
    where
        V: Into<bool>,
    {
        // Send the command
        self.driver
            .lock()
            .unwrap()
            .write(SwitchBinary::set(self.id, value))
    }

    /// The Binary Switch Command Class is used to control devices with On/Off
    /// or Enable/Disable capability.
    ///
    /// The Binary Switch Get command, version 1 is used to request the status
    /// of a device with On/Off or Enable/Disable capability.
    pub fn switch_binary_get(&self) -> Result<bool, Error> {
        let mut driver = self.driver.lock().unwrap();
        // Send the command
        driver.write(SwitchBinary::get(self.id))?;
        // read the answer and convert it
        match driver.read() {
            Ok(msg) => SwitchBinary::report(msg.data),
            Err(err) => Err(err),
        }
    }

    /// The Powerlevel Set Command is used to set the power level indicator value,
    /// which should be used by the node when transmitting RF, and the timeout for
    /// this power level indicator value before returning the power level defined
    /// by the application.
    ///
    /// The seconds defines how many seconds the device stays in the defined powerlevel.
    pub fn powerlevel_set<S, T>(&self, status: S, seconds: T) -> Result<u8, Error>
    where
        S: Into<PowerLevelStatus>,
        T: Into<u8>,
    {
        // Send the command
        self.driver
            .lock()
            .unwrap()
            .write(PowerLevel::set(self.id, status, seconds))
    }

    /// This command is used to advertise the current power level.
    ///
    /// Return the Powerlevel status and the time left on this power level.
    pub fn powerlevel_get(&self) -> Result<(PowerLevelStatus, u8), Error> {
        let mut driver = self.driver.lock().unwrap();
        // Send the command
        driver.write(PowerLevel::get(self.id))?;

        // read the answer and convert it
        match driver.read() {
            Ok(msg) => PowerLevel::report(msg.data),
            Err(err) => Err(err),
        }
    }

    /// The Powerlevel Test Node Set Command is used to instruct the destination node to transmit
    /// a number of test frames to the specified NodeID with the RF power level specified. After
    /// the test frame transmissions the RF power level is reset to normal and the result (number
    /// of acknowledged test frames) is saved for subsequent read-back. The result of the test may
    /// be requested with a Powerlevel Test Node Get Command.
    ///
    /// node_id: The node id where to send the message.
    /// test_node_id: The test NodeID that should receive the test frames.
    /// level: The power level indicator value to use in the test frame transmission.
    /// test_frames: The Test frame count field contains the number of test frames to transmit to
    ///              the Test NodeID. The first byte is the most significant byte.
    pub fn powerlevel_test_node_set<T, L, F>(
        &self,
        test_node_id: T,
        level: L,
        test_frames: F,
    ) -> Result<u8, Error>
    where
        T: Into<u8>,
        L: Into<PowerLevelStatus>,
        F: Into<u16>,
    {
        // Send the command
        self.driver.lock().unwrap().write(PowerLevel::test_node_set(
            self.id,
            test_node_id,
            level,
            test_frames,
        ))
    }

    /// This command is used to report the latest result of a test frame
    /// transmission started by the Powerlevel Test Node Set Command.
    ///
    /// Return the test node id, status of operation and the test frane count.
    pub fn powerlevel_test_node_get(&self) -> Result<(u8, PowerLevelOperationStatus, u16), Error> {
        let mut driver = self.driver.lock().unwrap();

        // Send the command
        self.driver
            .lock()
            .unwrap()
            .write(PowerLevel::test_node_get(self.id))?;

        // read the answer and convert it
        match driver.read() {
            Ok(msg) => PowerLevel::test_node_report(msg.data),
            Err(err) => Err(err),
        }
    }

    /// A meter is used to monitor a resource. The meter accumulates the resource flow over time.
    /// As an option, the meter may report not only the most recent accumulated reading but also
    /// the previous reading and the time that elapsed since then. A meter may also be able to
    /// report the current resource flow. This is known as the instant value.
    ///
    /// The Meter Get Command is used to request the accumulated consumption in physical units
    /// from a metering device.
    pub fn meter_get(&self) -> Result<MeterData, Error> {
        let mut driver = self.driver.lock().unwrap();
        // Send the command
        driver.write(Meter::get(self.id))?;

        // read the answer and convert it
        match driver.read() {
            Ok(msg) => Meter::report(msg.data),
            Err(err) => Err(err),
        }
    }

    /// A meter is used to monitor a resource. The meter accumulates the resource flow over time.
    /// As an option, the meter may report not only the most recent accumulated reading but also
    /// the previous reading and the time that elapsed since then. A meter may also be able to
    /// report the current resource flow. This is known as the instant value.
    ///
    /// The Meter Get Command is used to request the accumulated consumption in physical units
    /// from a metering device.
    pub fn meter_get_v2<S>(&self, meter_type: S) -> Result<(MeterData, u16, MeterData), Error>
    where
        S: Into<MeterData>,
    {
        let mut driver = self.driver.lock().unwrap();
        // Send the command
        driver.write(Meter::get_v2(self.id, meter_type.into()))?;

        // read the answer and convert it
        match driver.read() {
            Ok(msg) => Meter::report_v2(msg.data),
            Err(err) => Err(err),
        }
    }
}

impl<D> Clone for Node<D>
where
    D: Driver,
{
    /// We need to implement Clone manually because of a bugin rust
    fn clone(&self) -> Node<D> {
        Node {
            driver: self.driver.clone(),
            id: self.id,
            types: self.types.clone(),
            cmds: self.cmds.clone(),
        }
    }
}