Code Monkey home page Code Monkey logo

deprecated-taxonomy's People

Contributors

aosmond avatar azasypkin avatar cr avatar dhylands avatar fabricedesre avatar ferjm avatar hfiguiere avatar johanlorenzo avatar julienw avatar mcav avatar

Watchers

 avatar  avatar

deprecated-taxonomy's Issues

We need a way to properly shutdown the adapters

Currently drop functions are not called. This is likely because we don't stop the several threads we're running. One way to do this is to make the SHUTDOWN_FLAG public so that every threads can access it. But it wouldn't be nice for adapters that are in separate repositories.

Another way is to use a "stop" method on adapters, that would be called at the right time.

The openzwave adapter badly needs this.

Would be nice to be able to get string versions of ChannelKinds/Types in the adapters.

Following up on our discussion about FanOn, LightOn, etc.

I think it might be useful to be able to get at the FanOn/LightOn On/Off stuff as strings rather than as rust enums.

It sounds like we're going to wind up having many aliases for the same thing, which from the adapters point of view are all 100% identical. This means having a bunch of duplicated code in the adapter.

I'd rather have a file, or something which lists all of the strings which are actually aliases for one another and write the code once, and just append new aliases as they become available.

There isn't any place in my adapters where the enums are actually used in any kind of enum-meaningful way. The adapter basically has to translate each of the things which means on to true and off to false (or perhaps the inverse), so that it can send true/false to the device.

Also, for the zwave adapter, it will need to translate in both directions, since it will need to store some type of persistent mapping. For example, zwave knows that say Node 2 is a BinarySwitch. If the user has assigned that Node 2 controls a fan, and wishes to use FanOn, FanOff commands, then we need to persist that information someplace so that we can present Node 2 as a Fan in the getters & setters. So we're going to wind up having to persist the fact that its a Fan with FanOn/FanOff using strings as well, as well as adding getters and setters which allow the kind/type to changed.

Tags should be Id<TagId>

Currently, we represent tags as String. For performance, safety and memory usage, we should rather represent them using Id.

For this purpose:
1/ Define in devices.rs an empty type struct TagId;
2/ Find all occurrences of tags as String and replace them with Id<TagId>.

The mimetype should be an `Id`, rather than a `String`.

There will probably be very few distinct mimetypes in the system, and we don't want to confuse a mimetype string with something else.

So, in values.rs, in the definition of Binary, we should use Id<MimetypeId> instead of String for the mimetype. This way, once issue #11 has landed, we'll benefit automatically from string caching.

I'm not seeing a String ChannelKind.

Does this mean I have to create a custom kind to store strings?

For example, I need to add getters and setters to the camera to get/set the camera_name, the username and password, and we should probably have a location as well.

register_watch should take &mut self

When calling register_watch we likely need to modify some internal structures. For this "&mut self" is necessary, or we'll need to use a Cell which is very inconvenient -- and could be dangerous.

Add a PropertyBag to channels

Services have a property_bag, which is a HashMap<String, String>, immutable and provided during creation, that can contain data useful for the developer. We should have the same for channels.

Improve Service serialization

Right now the clock service is serialized as:

{
    "adapter": "[email protected]",
    "getters": {
      "getter:[email protected]": {
        "adapter": "[email protected]",
        "id": "getter:[email protected]",
        "kind": "CurrentTimeOfDay",
        "mechanism": "getter",
        "service": "service:[email protected]",
        "tags": []
      },
      "getter:[email protected]": {
        "adapter": "[email protected]",
        "id": "getter:[email protected]",
        "kind": "CurrentTime",
        "mechanism": "getter",
        "service": "service:[email protected]",
        "tags": []
      }
    },
    "id": "service:[email protected]",
    "properties": {
      "model": "Mozilla clock v1"
    },
    "setters": {},
    "tags": []
  }

I'd like getters to be an array to not repeat the getter id both as a property name and as an id value.

setter return value examples

An examples where the setter returns a value, would be when you issue a take_snapshot command.

This will create an image, and perhaps a getter. If it creates a getter, it would be nice to know the id of the getter which was just created (the id that corresponds to the snapshot I just took).

I think that this will be important for retrieving historical data. i.e. we record someplace that we took a picture at this time with this ID so that it can be retrieved later.

[RFC] Higher-level AdapterManager

Spinoff from an idea by @mcav in #53.

We could rewrite the AdapterManager's channel API as follows:

/// A channel, which may have read/write capabilities.
pub struct Channel {
  id: Id<Channel>,
  kind: ChannelKind,
  service: Id<ServiceId>,
  pub properties: PropertyBag,
  pub fetch: Option<Box< Fn(FetchArgs) -> Result<Value, Error> + Sync + Send>>,
  pub send: Option<Box< Fn(SendArgs) -> Result<(), Error> + Sync + Send>>,
  pub watch: Option<Box< Fn(WatchArgs) -> Result<WatchGuard, Error> + Sync + Send>>,
  // Possibly more in the future.
}
impl Channel {
  /// Create an empty channel.
  pub fn new(id: &Id<Channel>, service: &Id<ServiceId>, kind: ChannelKind) -> Self;
}

impl AdapterManger {
  pub fn add_channel(channel: Channel) -> Result<(), Error>
}

Pros

  • This relieves Adapters from having to maintain their own mapping between Id<Getter>/Id<Setter>, actual devices, actual implementation.
  • Extending this with future capabilities (e.g. delete) should be quite simple.
  • We can expose a data structure Channel much like this to the REST API, and it should often be easier to use than our current separate getters/setters.

Cons

  • The current AdapterManager manages to combine various fetch (respectively send, watch) requests by Adapter and send them together to minimize communications. I don't see how to do this with this design.

[RFC] Replace centralized channel-type definitions with encoded values.

Problem: The centralized enums of { ChannelType, Type, and Value } are tedious to extend, arbitrarily defined, and tend to be very adapter-specific.

Proposal: Rather than defining ChannelType, Type, and Value in centralized enums, we should pass around encoded values, allowing Adapters to decide how to decode that data, something like this:

struct EncodedValue {
  content_type: String, // e.g. “temperature+json”
  data: Vec<u8>
}

Adapters will decide how to decode EncodedValues themselves. This:

  • Simplifies the process of adding new adapters and channels;
  • Removes the burden of maintaining cumbersome centralized enums and serialization;
  • Maintains the notion of “typed” values in a very web-centric way;
  • Allows us to transport both binary and JSON data efficiently;
  • Allows channels to handle multiple content_types (e.g. image/*) rather than just one.

Content-Types

Standards already describe a time-tested way of exchanging typed data and defining content types. (While we could certainly go full-throttle with application/vnd.mozilla-temperature+json for things like “temperature” that haven’t been standardized, a simple temperature+json format would be plenty specific.)

Ultimately, we just want a Content-Type to allow the consumer to go from a binary representation to the type they desire. I suggest MIME Types because adapters can take advantage of standardized types (cameras with image/jpeg) and this pushes us toward a web-compatible direction.

Type-Checking and Code Sharing

I still see a role for taxonomy-like types with this approach. We can define types that need to be standardized and allow them to implement serialization to and from EncodedValue objects. This allows us to retain the existing level of type-safety some people prefer, without restricting authors to defining new types in a rigid global enum.

While there are clear benefits to enforcing types, I think we need to take a step back from this full-on, define-the-world-rigidly approach. I think this proposal would greatly simplify both the Taxonomy and FoxBox code, leaving us in a better position for growth and stability. If you disagree, I'd like to better understand the merits of the current method as compared to this proposal.

Example Content-Types

temperature+json => { “C”: 42 }
boolean => 0 | 1
thinkerbell-rule+json => { ... }
color+rgba => 255 255 255 0
color+json => { r: 0, g: 0, b: 0, a: 255 }
image/jpeg
null => (no data)

Finish porting tests and documentation to decentralized taxonomy

Branch decentralized contains a new version of Taxonomy, based on initial brainstorming between @mcav and myself. It now passes its main tests, but a number of doctests have not been ported to the new API yet.

Once work on this repo is done, I'd like to work on

  • porting Thinkerbell to Decentralized Taxonomy;
  • porting existing Adapters to Decentralized Taxonomy;
  • porting the REST API to Decentralized Taxonomy.

Before we can do that, however, we need to finish the work on this repo. @mcav, I don't know if you have some spare cycles at the moment, but I could use the help, both on this repo and on the followup work. I'm leaving on PTO for one week, so my ideal scenario would be one in which you have finished the work on this repo during the time and we can parallelize the rest when I return. If you prefer waiting until I return, I can understand, though.

Improve (de)serialization of ChannelKind

At the moment, most of the variants of ServiceKind are (de)serialized as key: [], with the exception of Extension. We should simply (de)serialize them as a string, with the exception of Extension being (de)serialized as an object.

getter parameter examples

I came up with some examples where having a getter take parameters would be useful:

1 - Retrieving an image with some type of conversion specifier (i.e. format jpeg/png, scaling factor)
2 - Retrieving historical sensor data and specifying a date/time range that you're interested in

Improve Binary

For the moment, we handle Binary as a Vec<u8> passed through JSON. That's pretty ugly, so we should find a better way to store Binaries.

  • One possibility would be to transmit them as a multipart request/response. I believe that fetch handles that nicely, but I haven't checked.
  • Another possibility would be to expose them as randomly-generated, refcounted + short-lived URIs.

Cc-ing people who had to deal with Binary: @dhylands , @azasypkin .

Move watcher logic from adapters to the adapter manager

Managing watchers requires significant portions of code in adapters that is beginning to look like massive boilerplate. Instead, managing watchers, range checking and notification should happen centrally in the adapter manager.

I suggest to have adapters declare on getter registration whether or not a getter support updates. One way to go about this might be to modify the return type to pass an optional mpsc channel that the adapter uses to inform the adapter manager of every update to the getter's value:

fn add_getter(&self, setter: Channel<Getter>) -> Result<Option<Sender<T>>, Error>;

That way we can completely remove register_watch() from the Adapter: Send trait and can have a well-tested central implementation of all the watcher logic.

Add a test script to rebuild everything

A few days ago, a problem on Taxonomy (on a personal branch, moreover), caused breakage on Foxbox for everyone.

To solve this issue – and get rid of all the problems we have with pinning Taxonomy – we need a script that gets Travis to rebuild Foxbox with a version of Taxonomy before we merge that version. This would considerably simplify the work of updating Taxonomy.

@JohanLorenzo Could you handle that?

Value::Bool is unhealthy

At the moment, we have a variant Value::Bool, which is used for determining whether a door is opened, a device is on, etc. That's ambiguous.

Rather, we should have:

  • Value::Opening(Opening) with enum Opening { Open, Closed };
  • Value::OnOff(OnOff), with enum OnOff { On, Off };
  • ...
  • and finally Value::ExtBool, with the same kind of structure as Value::ExtNumeric.

More powerful channel selectors

I'd like to write a Thinkerbell rule (or, really, any send operation) that turns off all lights in the living room. Let's assume that lights are defined by channels with kinds OnOff and Luminosity.

How can I do it?

  1. Sending Off to all channels that support OnOff in the living room can turn off devices that are not lights, so this is not what we want.
  2. Requesting the list of services that have channels OnOff and Luminosity, then taking the OnOff channels of such services gives us that list, but we need to rely upon the Id of services, which means that the rule will break when we replace the device.

We need better selectors.

Standardize, document and test (de)serialization

For the moment, we rely on Serde's #[derive(Serialize, Deserialize)]. This is very convenient, but:

  • the JSON produced/consumed is sometimes very surprising (see e.g. serde-rs/serde#251);
  • the JSON is neither documented nor tested.

Piece-by-piece and bottom-up, we should:

  • implement Serialize, Deserialize manually;
  • write doctests to specify & test the format.

Blocks

Channel Selectors should be able to select by service tag

One of the main use cases of tags is to let users label devices by their usecase and/or their location (e.g. "location: bedroom" or "usage: intrusion detector"). In most cases, users will probably want to label per Service, rather than per Channel.

To handle this, we need to update GetterSelector and SetterSelector to:

  • add a field selector_tags: HashSet<Id<TagId>>;
  • add a method pub fn with_selector_tags(self, HashSet<Id<TagId>>) -> Self;
  • replace pub fn matches(&self, &Channel<_>) -> bool with a pub fn matches(&self, &Channel<_>, &Service) -> bool that implements the actual selection.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.