You can also buy me a coffee here!
Before using Cocktail, we suggest to have a look to the documentation .
Within this repository we store all the necessary to start with a Semantic Web Of Things implementation.
Why Cocktail? Because you can prepare a cocktail with plenty of ingredients, which is what we do here: we prepare semantic systems with our ingredients, the interaction patterns.
To run, and use, the APIs for the Semantic Web of Things, you need
- A running SEPA instance
- The SEPA python3 APIs, available in sepy repository. Be Careful! Use the branch dev-0.9.5
Cocktail uses those APIs to post Things and their descriptions. In particular, you may
want to have a look to the SEPA.py python3 class.
As Cocktail builds up in SEPA's RDF knowledge base a Semantic WebThing Environment, a SEPA instance is required in almost every method within Cocktail.
Therefore, here an example of how to instantiate a SEPA:
- run the SEPA instance
- create a Cocktail SAP file. The SAP file is an entity related to SEPA, where all the information about how the application will interact with it is contained (IP-port, SPARQLs,...). Have a look to the tools available in this repository to create an YSAP (which stands for YAML-SAP).
- Code your application
with open(path_to_ysap_file, "r") as ysap_file:
ysap = SAPObject(yaml.load(ysap_file))
engine = SEPA(sapObject=ysap, logLevel=logging.ERROR)
or, if you prefer to use JSAP (which stands for JSON-SAP)
with open(path_to_jsap_file, "r") as jsap_file:
jsap = SAPObject(json.load(jsap_file))
engine = SEPA(sapObject=jsap, logLevel=logging.ERROR)
For more complex situations, please refer to sepy repo documentation or the various example available in this repository.
Once SEPA has been declared, you may want to define your first WebThing.
A WebThing is made up of some Actions, some Events, some Properties.
Additionally, there may be the possibility to declare their parameter's
DataSchema and FieldSchema. Therefore,
- Define your WebThing. So,
myThing = Thing(myEngine,bindings,superThing=None)
where superthing might be left unused, if your WebThing is not represented
on the Web by another WebThing. In such case, you would put here the URI
of that WebThing.
myEngine is the Sepa instance;
bindings is a python3 dictionary that should be formatted as in the
corresponding .sparql file. In that case,
bindings = {
"thing":"",
"newName":"",
"newTD":""
}
- Declare your Actions, calling
myAction = Action(myEngine,bindings,action_task,forProperties=[],force_type=None)
bindings, in this case, has to be formatted according to the .sparql
available in the updates folder. For instance, if you are creating an
IO Action, you would have
bindings = {
"td":"",
"action":"",
"newName":"",
"ids":"",
"ods":""
}
As you can see, the td field is required: this means that you need to
know prior to creating the Action (but also the other InteractionPatterns)
which is the WebThing you will connect this Action to. In the td entry you
will put the same URI that you put in the previous Thing newTD field.
action_task is the method you need to be run when a new Action Request
is detected. For this reason, it must be formatted either as a lambda expression
lambda added, removed: do_something_function()
either as a complete handler:
def do_something_function(added,removed)
forProperties is a list that may be empty. If you previously declared
some Properties, and you want to connect them to this action so that there
will be a <myAction> wot:forProperty <myProperty> triple, just put the
property in the list.
forceType will be discussed later.
- Declare your Properties, with
myProperty = Property(myEngine,bindings)
where in this case bindings is a python3 dictionary that can be inferred
from new_property.sparql. You might consider also to use the getBindingList
method.
- Declare your Events:
myEvent = Event(myEngine,bindings,forProperties=[],force_type=None)
with the same meaning of parameters.
- You can now post your WebThing like this:
myThing.post(interaction_patterns=[myAction,myEvent,myProperty])
Once the WebThing is posted to SEPA successfully, it is still not operational. You can enable Actions with the following command:
myAction.enable()
And you can notify Events with the following command:
myEvent.notify(bindings)
where bindings is a dictionary to be formatted as in new_empty_event_instance.sparql
(if your event is of EMPTY type), or as in new_o_event_instance.sparql
otherwise. To make an example:
bindings = {
"event":"",
"newEInstance":"",
"newOData":"",
"newValue":"",
"newDS":""
}
When it comes to discover what WebThings are available, just consider that
in Cocktail every class has its own discover static method. Therefore,
Property.discover(myEngine,prop="UNDEF",nice_output=False)
will output the result of a query available in property.sparql. You might
ask for a specific Property URI discovery changing the prop parameter.
Similarly,
Action.discover(sepa,action="UNDEF",nice_output=False)
Event.discover(sepa,event="UNDEF",nice_output=False)
DataSchema.discover(sepa,ds="UNDEF",nice_output=False)
While little difference in the prototype in discover method for
Thing.discover(sepa,bindings={},nice_output=False)
InteractionPattern.discover(sepa,td_uri="UNDEF",ip_type="UNDEF",nice_output=False)
where the bindings are given from the queries/things.sparql, and
for the InteractionPattern you might want to customize your discovery
with a specific ThingDescription URI, or to ask for discovery only for
Actions, Events or Properties.
To request an Action, you need to know a few informations about the Action
itself. This is possible by querying the knowledge base, and by building
up an image of the Action. An image of an Action is an Action that has the
inferred flag to True.
Internally, a call to isInferred() checks if there is a handler connected to
that Action. If not, it is an image (i.e., you are not the Action owner, but some external entity that what to interact with it).
You can retrieve an Action image with the following static method:
myActionImage = Action.buildFromQuery(myEngine,actionUri)
This call returns an Action so that myActionImage.isInferred() is True.
From that Action item, you can then call the request:
myActionImage.newRequest(bindings,confirm_handler=None,completion_handler=None,output_handler=None)
Whose parameters are the following:
bindings is a python3 dictionary that can be inferred from new_action_instance
SPARQLs file. As an example, in case the action is an I_Action:
bindings = {
"action":"",
"newAInstance":"",
"newAuthor":"",
"newIData":"",
"newIValue":"",
"newIDS":""
}
where you give the action uri, action instance uri, author uri, input data uri, input value, and input DataSchema.
TODO: some of these informations (action uri, author) may be already available!
confirm_handler is a method that is triggered when the confirmation flag
is inserted in the SEPA. completion_handler is a method triggered when
the confirmation flag is inserted in the SEPA. output_handler is another
method, called when the output of the execution is available. The three
methods are not compulsory, and should be given as lambdas, or functions
with added and removed parameters.
In order to receive the notification of an Event, the procedure is the following.
First of all, you have to retrieve an image of the Event, as we did for Actions. Therefore,
myEventImage = Event.buildFromQuery(myEngine,eventURI)
Once you have that image, you can start and stop observing notifications:
myEventImage.observe(handler)
myEventImage.stop_observing()
where handler is as usual a lambda, or a full handler for subscription
notification.
The usage of virtualenv might be a good idea, in that case :) First of all clone this repository. Install also sepy (for the future we aim to do this automatically).
$ cd path_to_repo_folder
$ cd ./cocktail_swot_framework/dist
$ pip3 install cocktail-1.tar.gz
For now, tests are available only to check ontology consistency.
$ python3 setup.py test
Notice that, if some SPARQL in the repo changes, it may be useful to reset the tests background. This is done by going to test folder and running
$ python3 reset_results.py
Some examples on how to build Semantic WebThings and how to make them interact are available in SWTE_example folder! There is a README to help you run the experiment of the paper (being submitted now).
In tools folder a ysap generation tool and a discovery tool are available as well. A README is provided.
Feel free to get in touch, if you have any question or suggestions, or if you find bugs!