Coder Social home page Coder Social logo

astarte-platform / astarte Goto Github PK

View Code? Open in Web Editor NEW
236.0 11.0 45.0 9.42 MB

Core Astarte Repository

Home Page: https://docs.astarte-platform.org/

License: Apache License 2.0

Shell 0.02% Dockerfile 0.26% Elixir 99.66% Euphoria 0.01% Nix 0.05%
iot-platform iot iot-framework iot-middleware hacktoberfest

astarte's Introduction

Astarte

codecov

Astarte is an Open Source IoT platform focused on Data management and processing written in Elixir. It is a turnkey solution which packs in everything you need for connecting a device fleet to a set of remote applications and process data as it flows through a set of built-in features.

It performs data modeling, automated data reduction, real-time events, and provides you with any feature you might expect in a modern IoT platform.

Astarte builds on top of amazing Open Source projects such as RabbitMQ and Cassandra/ScyllaDB.

Resources and Quickstart

Let's try it!

This is the master branch, which is not guaranteed to always be in a usable state.

For production purposes we recommend using the latest stable release (currently v1.1), this branch should be used only for v1.2 development activities.

Can't be easier. Pick your favorite machine with at least 4GB of free RAM, make sure it has Docker, and simply:

$ git clone https://github.com/astarte-platform/astarte.git && cd astarte
$ docker run -v $(pwd)/compose:/compose astarte/docker-compose-initializer:snapshot
$ docker compose pull
$ docker compose up -d

Make sure to use the latest stable release if you want a flawless experience.

You should be up and running in a matter of minutes. If you want a more thorough explanation and find out how to access your new Astarte cluster and what you can do with it, follow our "Astarte in 5 minutes" tutorial to get some fake or real devices to stream and process data while your tea gets ready.

Sweet! Let's move it to production!

Whoa, not so fast. Putting together an Astarte instance which can handle your data might be tricky, and requires some knowledge about the platform to make sure it won't break.

So, if you're serious about getting Astarte in your production environment, you might want to learn more about it first. Start by having a look at its architecture and finding out how it works. Once you feel confident, head over to the Administration Manual.

Where do I find binaries?

Astarte is designed from the ground up to be run in containers, with Kubernetes as a first-class citizen when it comes to deployment. Astarte's images can be found at Docker Hub, with every Astarte service coming with its own image.

With the help of our Kubernetes Operator and astartectl, you can deploy your Astarte instance to your favorite cloud provider in a matter of minutes.

Looks great! I want to contribute!

That's awesome! Astarte is quite young as an Open Source project, so we're still setting up bits and pieces to make contributions easier and more effective, such as a shared roadmap, a proper contributor guide. For the time being, you can head over to the repository you want to contribute to and set up a Pull Request. We're using DCO for our contributions, so you'll need to sign off all commit messages before submitting a Pull Request.

You can also join us on #astarte slack channel on Elixir Slack and on #astarte IRC channel on freenode.

We accept all kind of quality contributions, as long as they adhere with the project goals and philosophy, and have some tests.

Any chance I can get a hosted and managed instance?

Yup, stay tuned :) or get in touch with us.

I need some help with my installation! Where can I get commercial support?

Glad you asked. Astarte is developed by SECO Mind, who fuels its development thanks to the generosity of many customers running it in production. Besides consultancy, installation, maintenance, long-term support and customizations, SECO Mind also commercializes Astarte Enterprise, an Astarte variant packing in some additional goodies and features.

Get in touch or contact us via email to find out how we can help you in getting Astarte in its best possible shape for your specific needs.

License

Astarte source code is released under the Apache 2 License.

Check the LICENSE file for more information.

astarte's People

Contributors

annopaolo avatar arahmarchak avatar atsetilam avatar bettio avatar davidebriani avatar drf avatar eddbbt avatar hibe7 avatar lucaato avatar matt-mazzucato avatar nanjarapalli avatar nedimtokic avatar noaccos avatar osmanhadzic avatar pavinati avatar rbino avatar shinnokdisengir avatar sorru94 avatar spidey20202022 avatar szakhlypa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

astarte's Issues

Load :any_interface data triggers

RIght now, triggers having as target the special * interface can be installed, but DataUpdater never loads them in its state to use them.

DataUpdater should do something like

any_interface_id = SimpleTriggersProtobufUtils.any_interface_object_id()
populate_triggers_for_object!(new_state, db_client, any_interface_id, :any_interface)

This should probably be done in reload_device_triggers_on_expiry since these triggers don't depend on a specific interface and/or introspection.

Error running Astarte in 5 minutes

Hey! I am trying to go through with 5 minutes tutorial, but I have a problem with test realm creation.

After generating a key, I run this command and get:

openssl rsa -in test_realm.key -pubout -outform PEM -out test_realm.key.pub
unable to load Private Key
4682208876:error:09FFF06C:PEM routines:CRYPTO_internal:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.240.1/libressl-2.6/crypto/pem/pem_lib.c:683:Expecting: ANY PRIVATE KEY

I am running latest mac os x with openssl installed with brew:

openssl version
LibreSSL 2.6.5

How to properly deal with this problem?

Implement sensors plot JS example

Implement a JavaScript example which allows to choose a sensor and to plot a chart for the given interval. The example should also display min, max and average values.
All data should be displayed along with units and sensor names.

The example should use cloud.astarte.genericsensors.Values properties interface and cloud.astarte.genericsensors.AvailableSensors (when available). It would be useful to implement it using React as well.

See also #86

docker-compose doesn't persist CA configuration

If you execute docker-compose down and docker-compose up on an Astarte instance, all certificates emitted before the restart are seen as invalid (with an Unknown CA error).
The devices eventually reconnect since they verify the certificate, but this has to be investigated.

Add metadata to device

Add a metadata collection to device.
Metadata will allow to store arbitrary string value associated to arbitrary keys.

Example:

{
    "id": "7RrWVRVAQcmChzSokqYwmQ"
    "connected": true,
    [...]
    "metadata": {
        "customer_id": "123456789",
        "hide": "false"
    }
}

Describe some real world use cases

Documentation should contain some how-tos for following scenarios:

  • A device with some sensors.
  • A device which collects data from some wireless sensors and delivers them to Astarte (with trade-off discussion: 1 device_id or multiple device_ids).
  • A remote controllable device (e.g. on/off relay).

See also:

Original samples count should be reported when using downsampling

Original samples count should be reported when using downsampling, this information is needed to know if additional data points can be retrieved on a smaller time window without performing any additional request.
metadata field should be used for this purpose.

Write a tutorial based on generic sensors interfaces

Write a tutorial based on generic sensors interfaces with JavaScript snippets from existing examples.

The tutorial should show:

  • Explain employed interfaces and their mappings
  • How to install required interfaces using astartectl or the dashboard
  • How to simulate a device which published data to those interfaces
  • How to display device status using the dashboard
  • How to download data using astartectl
  • API requests examples
  • JavaScript snippets based on existing examples
  • How to make a physical device using ESP32 SDK

See also:

Data Updater Plant crashes with `value_change` triggers on datastream interfaces

Stacktrace (generated with local Astarte deployment with 0.10-snapshot):

astarte-data-updater-plant_1    | 11:48:08.044 [error] GenServer {Registry.DataUpdater, {"test", <<201, 218, 129, 148, 91, 6, 67, 239, 177, 103, 239, 222, 125,
 12, 110, 47>>}} terminating
astarte-data-updater-plant_1    | ** (FunctionClauseError) no function clause matching in Astarte.DataAccess.Data.fetch_property/5
astarte-data-updater-plant_1    |     (astarte_data_access) lib/astarte_data_access/data.ex:37: Astarte.DataAccess.Data.fetch_property({#PID<0.1721.0>, #Refere
nce<0.3067377248.121896968.132174>}, <<201, 218, 129, 148, 91, 6, 67, 239, 177, 103, 239, 222, 125, 12, 110, 47>>, %Astarte.Core.InterfaceDescriptor{aggregatio
n: :individual, automaton: {%{{0, "realValue"} => 1}, %{1 => <<74, 19, 138, 223, 180, 26, 70, 196, 99, 119, 165, 221, 187, 187, 72, 163>>}}, interface_id: <<2,
 224, 206, 164, 78, 230, 132, 21, 68, 58, 174, 138, 98, 46, 5, 104>>, major_version: 0, minor_version: 1, name: "org.astarteplatform.Values", ownership: :devic
e, storage: "individual_datastreams", storage_type: :multi_interface_individual_datastream_dbtable, type: :datastream}, %Astarte.Core.Mapping{allow_unset: fals
e, description: nil, doc: nil, endpoint: "/realValue", endpoint_id: <<74, 19, 138, 223, 180, 26, 70, 196, 99, 119, 165, 221, 187, 187, 72, 163>>, expiry: 0, ex
plicit_timestamp: true, interface_id: <<2, 224, 206, 164, 78, 230, 132, 21, 68, 58, 174, 138, 98, 46, 5, 104>>, path: nil, reliability: :unreliable, retention:
 :discard, type: nil, value_type: :double}, "/realValue")
astarte-data-updater-plant_1    |     (astarte_data_updater_plant) lib/astarte_data_updater_plant/data_updater/impl.ex:346: Astarte.DataUpdaterPlant.DataUpdate
r.Impl.handle_data/6
astarte-data-updater-plant_1    |     (astarte_data_updater_plant) lib/astarte_data_updater_plant/data_updater/server.ex:53: Astarte.DataUpdaterPlant.DataUpdat
er.Server.handle_cast/2
astarte-data-updater-plant_1    |     (stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
astarte-data-updater-plant_1    |     (stdlib) gen_server.erl:686: :gen_server.handle_msg/6
astarte-data-updater-plant_1    |     (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
astarte-data-updater-plant_1    | Last message: {:"$gen_cast", {:handle_data, "org.astarteplatform.Values", "/realValue", <<12, 0, 0, 0, 16, 118, 0, 8, 0, 0, 0
, 0>>, "test-ydqBlFsGQ--xZ-_e-37E77026732BBA-724F1B33", 15735592586521530}}
astarte-data-updater-plant_1    | State: %Astarte.DataUpdaterPlant.DataUpdater.State{connected: true, data_triggers: %{}, datastream_maximum_storage_retention:
 nil, device_id: <<201, 218, 129, 148, 91, 6, 67, 239, 177, 103, 239, 222, 125, 12, 110, 47>>, device_triggers: %{}, interface_ids_to_name: %{}, interfaces: %{
}, interfaces_by_expiry: [], introspection: %{"org.astarteplatform.Values" => 0}, introspection_triggers: %{}, last_device_triggers_refresh: 0, last_seen_messa
ge: 0, mappings: %{}, message_tracker: #PID<0.1707.0>, paths_cache: {32, %{}}, realm: "test", total_received_bytes: 9089, total_received_msgs: 93, volatile_tri
ggers: []}
astarte-data-updater-plant_1    |
astarte-data-updater-plant_1    | =CRASH REPORT==== 12-Nov-2019::11:48:08 ===
astarte-data-updater-plant_1    |   crasher:
astarte-data-updater-plant_1    |     initial call: Elixir.Astarte.DataUpdaterPlant.DataUpdater.Server:init/1
astarte-data-updater-plant_1    |     pid: <0.1858.0>
astarte-data-updater-plant_1    |     registered_name: []
astarte-data-updater-plant_1    |     exception error: no function clause matching
astarte-data-updater-plant_1    |                      'Elixir.Astarte.DataAccess.Data':fetch_property({<0.1721.0>,
astarte-data-updater-plant_1    |                                                                       #Ref<0.3067377248.121896968.132174>},
astarte-data-updater-plant_1    |                                                                      <<201,218,
astarte-data-updater-plant_1    |                                                                        129,148,
astarte-data-updater-plant_1    |                                                                        91,6,67,
astarte-data-updater-plant_1    |                                                                        239,177,
astarte-data-updater-plant_1    |                                                                        103,239,
astarte-data-updater-plant_1    |                                                                        222,125,
astarte-data-updater-plant_1    |                                                                        12,110,
astarte-data-updater-plant_1    |                                                                        47>>,
astarte-data-updater-plant_1    |                                                                      #{'__struct__' =>
astarte-data-updater-plant_1    |                                                                            'Elixir.Astarte.Core.InterfaceDescriptor',
astarte-data-updater-plant_1    |                                                                        aggregation =>
astarte-data-updater-plant_1    |                                                                            individual,
astarte-data-updater-plant_1    |                                                                        automaton =>
astarte-data-updater-plant_1    |                                                                            {#{{0,
astarte-data-updater-plant_1    |                                                                                <<"realValue">>} =>
astarte-data-updater-plant_1    |                                                                                   1},
astarte-data-updater-plant_1    |                                                                             #{1 =>
astarte-data-updater-plant_1    |                                                                                   <<74,19,
astarte-data-updater-plant_1    |                                                                                     138,223,
astarte-data-updater-plant_1    |                                                                                     180,26,
astarte-data-updater-plant_1    |                                                                                     70,196,
astarte-data-updater-plant_1    |                                                                                     99,119,
astarte-data-updater-plant_1    |                                                                                     165,221,
astarte-data-updater-plant_1    |                                                                                     187,187,
astarte-data-updater-plant_1    |                                                                                     72,163>>}},
astarte-data-updater-plant_1    |                                                                        interface_id =>
astarte-data-updater-plant_1    |                                                                            <<2,224,
astarte-data-updater-plant_1    |                                                                              206,164,
astarte-data-updater-plant_1    |                                                                              78,230,
astarte-data-updater-plant_1    |                                                                              132,21,
astarte-data-updater-plant_1    |                                                                              68,58,
astarte-data-updater-plant_1    |                                                                              174,138,
astarte-data-updater-plant_1    |                                                                              98,46,5,
astarte-data-updater-plant_1    |                                                                              104>>,
astarte-data-updater-plant_1    |                                                                        major_version =>
astarte-data-updater-plant_1    |                                                                            0,
astarte-data-updater-plant_1    |                                                                        minor_version =>
astarte-data-updater-plant_1    |                                                                            1,
astarte-data-updater-plant_1    |                                                                        name =>
astarte-data-updater-plant_1    |                                                                            <<"org.astarteplatform.Values">>,
astarte-data-updater-plant_1    |                                                                        ownership =>
astarte-data-updater-plant_1    |                                                                            device,
astarte-data-updater-plant_1    |                                                                        storage =>
astarte-data-updater-plant_1    |                                                                            <<"individual_datastreams">>,
astarte-data-updater-plant_1    |                                                                        storage_type =>
astarte-data-updater-plant_1    |                                                                            multi_interface_individual_datastream_dbtable,
astarte-data-updater-plant_1    |                                                                        type =>
astarte-data-updater-plant_1    |                                                                            datastream},
astarte-data-updater-plant_1    |                                                                      #{'__struct__' =>
astarte-data-updater-plant_1    |                                                                            'Elixir.Astarte.Core.Mapping',
astarte-data-updater-plant_1    |                                                                        allow_unset =>
astarte-data-updater-plant_1    |                                                                            false,
astarte-data-updater-plant_1    |                                                                        description =>
astarte-data-updater-plant_1    |                                                                            nil,
astarte-data-updater-plant_1    |                                                                        doc =>
astarte-data-updater-plant_1    |                                                                            nil,
astarte-data-updater-plant_1    |                                                                        endpoint =>
astarte-data-updater-plant_1    |                                                                            <<"/realValue">>,
astarte-data-updater-plant_1    |                                                                        endpoint_id =>
astarte-data-updater-plant_1    |                                                                            <<74,19,
astarte-data-updater-plant_1    |                                                                              138,223,
astarte-data-updater-plant_1    |                                                                              180,26,
astarte-data-updater-plant_1    |                                                                              70,196,
astarte-data-updater-plant_1    |                                                                              99,119,
astarte-data-updater-plant_1    |                                                                              165,221,
astarte-data-updater-plant_1    |                                                                              187,187,
astarte-data-updater-plant_1    |                                                                              72,163>>,
astarte-data-updater-plant_1    |                                                                        expiry =>
astarte-data-updater-plant_1    |                                                                            0,
astarte-data-updater-plant_1    |                                                                        explicit_timestamp =>
astarte-data-updater-plant_1    |                                                                            true,
astarte-data-updater-plant_1    |                                                                        interface_id =>
astarte-data-updater-plant_1    |                                                                            <<2,224,
astarte-data-updater-plant_1    |                                                                              206,164,
astarte-data-updater-plant_1    |                                                                              78,230,
astarte-data-updater-plant_1    |                                                                              132,21,
astarte-data-updater-plant_1    |                                                                              68,58,
astarte-data-updater-plant_1    |                                                                              174,138,
astarte-data-updater-plant_1    |                                                                              98,46,5,
astarte-data-updater-plant_1    |                                                                              104>>,
astarte-data-updater-plant_1    |                                                                        path =>
astarte-data-updater-plant_1    |                                                                            nil,
astarte-data-updater-plant_1    |                                                                        reliability =>
astarte-data-updater-plant_1    |                                                                            unreliable,
astarte-data-updater-plant_1    |                                                                        retention =>
astarte-data-updater-plant_1    |                                                                            discard,
astarte-data-updater-plant_1    |                                                                        type =>
astarte-data-updater-plant_1    |                                                                            nil,
astarte-data-updater-plant_1    |                                                                        value_type =>
astarte-data-updater-plant_1    |                                                                            double},
astarte-data-updater-plant_1    |                                                                      <<"/realValue">>) (lib/astarte_data_access/data.ex, line
 37)
astarte-data-updater-plant_1    |       in function  'Elixir.Astarte.DataUpdaterPlant.DataUpdater.Impl':handle_data/6 (lib/astarte_data_updater_plant/data_upda
ter/impl.ex, line 346)
astarte-data-updater-plant_1    |       in call from 'Elixir.Astarte.DataUpdaterPlant.DataUpdater.Server':handle_cast/2 (lib/astarte_data_updater_plant/data_up
dater/server.ex, line 53)
astarte-data-updater-plant_1    |       in call from gen_server:try_dispatch/4 (gen_server.erl, line 616)
astarte-data-updater-plant_1    |       in call from gen_server:handle_msg/6 (gen_server.erl, line 686)
astarte-data-updater-plant_1    |     ancestors: ['Elixir.Astarte.DataUpdaterPlant.AMQPDataConsumer',
astarte-data-updater-plant_1    |                   'Elixir.Astarte.DataUpdaterPlant.Supervisor',<0.1527.0>]
astarte-data-updater-plant_1    |     message_queue_len: 0
astarte-data-updater-plant_1    |     messages: []
astarte-data-updater-plant_1    |     links: [<0.1532.0>]
astarte-data-updater-plant_1    |     dictionary: []
astarte-data-updater-plant_1    |     trap_exit: false
astarte-data-updater-plant_1    |     status: running
astarte-data-updater-plant_1    |     heap_size: 2586
astarte-data-updater-plant_1    |     stack_size: 27
astarte-data-updater-plant_1    |     reductions: 6758
astarte-data-updater-plant_1    |   neighbours:

Implement SamplingRate JS example

Implement a JavaScript example which allows to enable and disable sensors and to configure sampling period.

The example should use cloud.astarte.genericsensors.SamplingRate properties interface. It would be useful to implement it using React as well.

See also #86

Implement sensors viewer JS example

Implement a JavaScript/HTML5 example which allows to display latest received values for each sensor.
It should also display sensor name and units when available.

The example should use cloud.astarte.genericsensors.Values properties interface and cloud.astarte.genericsensors.AvailableSensors (when available). It would be useful to implement it using React as well.

It is required to implement it in the most simple and clear way, so it can be used as a starting point for third party users.

See also #86

Allow access to previous interfaces data

When an interface major on a certain device is replaced by a newer one, older data is not accessible anymore, add an API which allows to retrieve older data too.

Revamp AppEngine API

AppEngine's API is currently too cumbersome and prevents some use cases from being fulfilled. Come up with a new design with is backwards compatible with 0.10.

Provide an Open Source IoT Platform unironically

As of the day this issue was opened, there's plenty of choices when it comes to developing IoT projects ironically, but there's a lack of concrete resources when one has to break through the layers of irony and face production.

We have to make sure developers can rely on a non-ironic solution.

Add stats to Groups

The same stats to be found for /stats/devices, should also be available for /stats/groups/

Provide a set of ready to use interfaces

Astarte should provide a set of ready to install and user interfaces that can be used as an example and can be without further effort:

{
    "interface_name": "org.astarte-platform.standard-interfaces.GenericSensor",
    "version_major": 1,
    "version_minor": 0,
    "type": "datastream",
    "ownership": "device",
    "mappings": [
        {
            "endpoint": "/%{sensor_id}/value",
            "type": "double"
        }
    ]
}
    "interface_name": "org.astarte-platform.standard-interfaces.AvailableSensors",
    "version_major": 1,
    "version_minor": 0,
    "type": "property",
    "ownership": "device",
    "mappings": [
        {
            "endpoint": "/%{sensor_id}/name",
            "type": "string"
        },
        {
            "endpoint": "/%{sensor_id}/unit",
            "type": "string"
        }
    ]
}

Implement sensors viewer WebSocket + JS example

Implement a JavaScript example which allows to choose a sensor and to display real time data using a WebSocket.

The example should use cloud.astarte.genericsensors.Values properties interface and cloud.astarte.genericsensors.AvailableSensors (when available). It would be useful to implement it using React as well.

See also #86

Downsample not working with format=disjoint_tables

example.com/appengine/v1/test/devices/test_device_id/interfaces/com.example.ObjectAggregated/param/0/value?format=disjoint_tables&keep_milliseconds=true&since=2018-09-12T18:53:50.302Z&to=2018-10-14T20:32:51.490Z&downsample_to=769

Returns an array with 10000 elements instead of 769.

Enhance Channels authorization mechanism

Currently, the JOIN and WATCH claim in a token are intertwined. This is bad design from an auth POV, where it is not acceptable that one credential implies another.

A proposed solution could be something like WATCH:<regex room>:<regex path>, which would keep JOIN standalone and WATCH self-fulfilling. As such, a claim like ["JOIN:.*", "WATCH:myroom:mydevice.*"] would be safe and meaningful.

Add support for the device_error device event

There's already a partial support for an additional device event (other than device_connected and device_disconnected) that is device_error.

Now that support for device logs is being added to the dashboard, it would be nice to use it to be able to expose errors happening inside Data Updater Plant (e.g. invalid topics, invalid data type etc) happening for a specific device, without having to look at the logs.

Adding empty endpoint causes internal server error

Steps to reproduce:
Install an interface with an empty string as endpoint.

{
    "interface_name": "myInterface",
    "version_major": 0,
    "version_minor": 1,
    "type": "properties",
    "ownership": "device",
    "mappings": [
        {
            "endpoint": "",
            "type": "longinteger"
        }
    ]
}

Missing /v1 in socket route

Right now to connect to an Astarte channel the url used is
%{appengine_url}/socket

We should uniform it to other Astarte routes like
%{appengine_url}/v1/socket

Support initial values in Pairing

Pairing already supports delivering an initial introspection. When this is done, it should also be possible to set initial values on all interfaces.

As an example, suppose we're registering a device with an interface com.example.Info in its initial introspection. A pairing API call should support something like:

[...]
"initial_data": {
    "com.example.Info": {
         "serial": "1491414"
    }
}
[...]

After registering the device, calling AppEngine API on the /com.example.Info/serial endpoint should return the value set, even if the device never connected.

[meta] org.astarte-platform.InterfaceName is not a valid interface name

- are not allowed in interface names right now, they should be allowed if we want to allow org.astarte-platform.InterfaceName.

I suggest following change:

  • - is allowed in any domain components (e.g. org.astarte-platform).
  • - is disallowed in the last interface name token (e.g. InterfaceName).

This will keep the interface name programmer friendly (e.g. interface name can be always mapped to a class or module name), while this limitation might be removed in future releases.

Related issues:

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.