Introduction¶
Iotic Agent In Brief¶
The IoticAgent module is the route from your code to Iotic Space. There’s a simple API built around concepts similar to those used in social networking for humans. For example, you can follow someone else’s feed and share your own.
This brief guide shows a quick way to get started coding. It does not attempt to be an exhaustive introduction to all the code. Follow the links on the left to see more detail.
Getting Started - Installation¶
The simplest installation guide is the README on GitHub.
Head there now to install, then come back here.
Getting Started - Environment - Note on PYTHONPATH¶
If you install from Git, or use an advanced pip install technique, you will need to be careful that PYTHONPATH is set to where you’ve installed the IoticAgent and any dependencies.
- If you used pip to install from PyPI and didn’t specify a directory in which to install, you don’t need to do anything.
- If you cloned github or used pypi with the -t option, then you’ll need to tell python where to look for the modules you’ve installed. See the Install from Git instructions on GitHub
Coding - Minimum script¶
Create a new Python script in the src directory with the following lines. This is the minimal Iotic Agent. Let’s call it my_script.py for now.
from IoticAgent import IOT
with IOT.Client() as client:
pass
You can, if you want, specify the config file in the call to Client()
from IoticAgent import IOT
with IOT.Client(config="my_script.ini") as client:
pass
More details: IoticAgent.IOT.Client module
Coding - Initialisation (ini) file¶
If you run this script on its own it will cause an exception on start with a helpful message:
Exception: Minimum configuration for IoticAgent is epId, passwd and token
Create or download from the Iotic Space website file new_agent/src/my_script.ini with contents
[agent]
epid = x
passwd = y
token = z
Where x, y and z are the epid, passwd and token from your owner.
Coding - Running your script¶
$ python3 my_script.py
The minimum script will connect and then wait for incoming messages. CTRL+C will stop it, as it’s not very useful at the moment.
Coding - Logging¶
The IoticAgent uses the Python logging module to raise messages to the user. Most of these you can ignore and, by default, no logging is shown. To setup logging in your script add the following lines at the top of your minimal agent.
import logging
logging.basicConfig(format='%(asctime)s,%(msecs)03d %(levelname)s [%(name)s] {%(threadName)s} %(message)s',
level=logging.WARNING)
This will show Warning, Error and Critical messages only. The next most verbose level is logging.INFO which is used to show functions you’ve called and any extra information a human user might like for normal development. There is one more level of logging (logging.DEBUG) which shows all the information about everything which will be too verbose for most people.
Coding - Wiring up the catchall callback¶
When feeddata arrives at your minimal Agent it will show a message at logging.WARNING level like:
Received Feed Data for Point GUID <long-string-of-numbers> but no callback registered."
The IoticAgent.IOT.Client provides a catchall feature for incoming feed data and control request messages that you haven’t got round to wiring up yet.
def catchall_feeddata(data):
print("catchall_feeddata:", data)
with IOT.Client(config="my_script.ini") as client
client.register_catchall_feeddata(catchall_feeddata)
Anytime any feed data arrives at this Agent the callback_feeddata (or whatever you want to call it) function will be called.
Note
client.reqister_callback_controlreq(fn) works the same way for control requests.
More details: IoticAgent.IOT.Client module
Coding - Make a thing¶
You can create a thing programmatically by calling create_thing() on your client instance. This method returns an iotic thing object which you should keep for future use.
thing_solar_panels = client.create_thing("SolarPanels")
This will create you a thing with a “local id” of SolarPanels. Think of the local id as a nickname for your thing It is for your use only and only on the container where your created it. No-one else on the system will know this name, be able to search for it or use it.
You can give your thing more descriptive information - see Describe your things and feeds in metadata below
More details: IoticAgent.IOT.Client module
Coding - Create a feed on your thing¶
Now’s the time to get your thing to advertise its wares. Call create_feed() on your thing instance and give it a local id. the same rules apply about this local id as before. Keep the returned iotic feed object for use later.
feed_current_values = thing_solar_panels.create_feed("Current Values")
More details: IoticAgent.IOT.Thing module
Coding - Following someone else’s feed¶
To follow someone else’s feed, first you need to know the feed’s Globally Unique ID or GUID. You can get this by searching the space on the web UI or they could email it to you. Then you call follow() on your thing object for their remote feed. You’ll also have to specify the callback function you want the agent to call for you when they next publish that feed.
# Args is a dict containing data and other details. See Thing.follow() for more information.
def feeddata_cb(args):
print("feeddata_cb", args['data'])
r_current_values_GUID = "long-string-of-numbers" # other feed's GUID
r_feed_current_values = thing_solar_panels.follow(r_current_values_GUID,
callback=feeddata_cb)
More details: IoticAgent.IOT.Thing module
Coding - Simulating someone else’s feed¶
You might be wondering why you want to remember the RemoteFeed object (r_feed_current_values in the code). This can be useful if they don’t publish often and you want to simulate their publishes in your code for testing.
Call simulate() on the remote feed object like so:
try:
r_feed_current_values.simulate()
except Exception:
pass # didn't have anything to simulate
Your callback function will be called with the last value that was received. The try/except block is necessary as simulate() will raise an exception if it’s got nothing to simulate - normally because you’ve never received anything and it can’t just make something up.
More details: IoticAgent.IOT.RemotePoint module
Coding - Following one of your own feeds¶
For anything to do with your own things, feeds and controls you can refer to them by their nickname. So to follow a feed on one of your own things, call follow() with the a tuple containing the nicknames of your thing/feed and your callback.
thing_solar_panels_receiver.follow(("SolarPanels","Current Values"),
callback=feeddata_cb)
More details: IoticAgent.IOT package
Coding - Describe your things and feeds in metadata¶
The Iotic infrastructure makes great use of semantic metadata to provide meaning for your things, Points and your Points’ values. You can get a metadata helper object from your Thing (or Feed) and describe the Thing in more detail. The label and description fields are free-text searchable so put information in them that will help others to find them. The geo-location of your Thing is used if others perform a location-based search.
Note
Your metadata is only searchable by others if you call IoticAgent.IOT.Thing.Thing.set_public. This allows you some granularity on what you choose to make available to others.
#!python
with thing_solar_panels.get_meta() as meta_thing_solar_panels:
meta_thing_solar_panels.set_label("Mark's Solar Panels")
meta_thing_solar_panels.set_description("Solar Array 3.3kW")
meta_thing_solar_panels.set_location(52.1965071,0.6067687)
# Optionally set the Thing to be public so that others can search for it.
thing_solar_panels.set_public()
More details:
Coding - Describe the contents of your feed in metadata¶
One of the most useful things you can do in metadata is to let the receiving parties of your feed data know what the contents of your feed are and their data type and units. There are a couple of extra, helpful modules you can import from the IoticAgent at the top of your code:
from IoticAgent import IOT, Units, Datatypes
Then you can specify the contents of your feed in more explicit detail. Call create_value() on your feed object.
feed_current_values.create_value("timestamp", Datatypes.DATETIME,
"en", "time of reading")
feed_current_values.create_value("power", Datatypes.DECIMAL,
"en", "output power in watts",
Units.WATT)
feed_current_values.create_value("current", Datatypes.DECIMAL,
"en", "dc current in amps",
Units.AMPERE)
feed_current_values.create_value("voltage", Datatypes.DECIMAL,
"en", "dc potential in volts",
Units.VOLT)
feed_current_values.create_value("temperature", Datatypes.DECIMAL,
"en", "array temperature in celsius",
Units.CELSIUS)
More details: IoticAgent.IOT.Point module
Coding - Create a control on your Thing¶
You can also make your Thing respond to activation requests by creating a control and its associated callback. Call create_control on your Thing object. A control like the opposite of a feed. It’s a way that other Things can send you data or ask your Thing to perform some action(s).
def reset_callback(args):
print("resetting counters")
panels.zero_counters()
thing_solar_panels.create_control("Reset Counters", reset_callback)
When somebody else activates your control with an ask() or tell(), then your callback will be called.
args is a dict containing control data and other details. See IoticAgent.IOT.Thing module for more information.
Coding - Attaching to a remote control¶
Attaching to a remote control is a bit like following-ing a feed, except the functions is attach() on the remote Thing. Once you’ve attached, you can call ask() or tell() on your RemoteControl object.
r_counters_GUID = "long-string-of-numbers" # GUID of remote control
r_control_counters = thing_solar_panels.attach(r_counters_GUID)
...
r_control_counters.ask(<payload>) #activate the remote control
The two similar functions ask() and tell() differ in that ask() is doesn’t require a confirmation that the action has been done, but tell() has a callback to be informed when the far end has done the action and a time-out so you can be informed if they haven’t done it in the time you require.
As you might expect, the attach function works for controls on Things you own. Use the tuple of (thing_nickname,control_nickname) to identify the control instead of the GUID
Coding - Which Exceptions¶
Parameters are validated on request and raise built-in ValueError.
Network failures raise IoticAgent.Core.Exceptions.LinkException which can be imported from IoticAgent.IOT.Exceptions for convenience.
If a request response from Iotic Space contains (FAILED)
IoticAgent.IOT.Exceptions.IOTUnknown (Unknown resource EG Thing not found)
IoticAgent.IOT.Exceptions.IOTMalformed (Not allowed resource, malformed request)
IoticAgent.IOT.Exceptions.IOTInternalError (Container internel error)
IoticAgent.IOT.Exceptions.IOTAccessDenied (ACL restriction)