Line 10: |
Line 10: |
| There are 3 basic node types in things bus: | | There are 3 basic node types in things bus: |
| | | |
− | * Sensors. Sensors produce data | + | * Sensors. Sensors produce data |
− | * Actuators. Data Sinks consume data, and probably do something interesting with it. | + | * Actuators. Data Sinks consume data, and probably do something interesting with it. |
− | * Neurons. Neurons take in sensory data, manipulate it in some way, and send the data to actuators. | + | * Neurons. Neurons take in sensory data, manipulate it in some way, and send the data to actuators. |
| | | |
| === Sensors === | | === Sensors === |
| | | |
− | A simple of an example of a sensor would be a temperature sense in the space. A temperature sensor would be a Raspberry Pi hooked into a temperature sense, and would send out the current temperature every 5 minutes. | + | A simple of an example of a sensor would be a temperature sense in the space. A temperature sensor would be a Raspberry Pi hooked into a temperature sense, and would send out the current temperature every 5 minutes. |
| | | |
| Sensors make data available by using a zmq bind PUB socket. | | Sensors make data available by using a zmq bind PUB socket. |
Line 22: |
Line 22: |
| === Actuators === | | === Actuators === |
| | | |
− | An Actuator is something that, when triggered, does something. It doesn't have to be physical. An actuator could be as simple as an led wired into a Raspberry Pi that can be triggered by a Neuron. | + | An Actuator is something that, when triggered, does something. It doesn't have to be physical. An actuator could be as simple as an led wired into a Raspberry Pi that can be triggered by a Neuron. |
| | | |
| Actuators consume data by using a zmq bind PULL socket | | Actuators consume data by using a zmq bind PULL socket |
Line 41: |
Line 41: |
| Examples: | | Examples: |
| | | |
− | * A Dust Collection Node would likely be both a sensor (Is it on?) and an actuator (Turn it on) | + | * A Dust Collection Node would likely be both a sensor (Is it on?) and an actuator (Turn it on) |
| | | |
| == A Simple Example == | | == A Simple Example == |
| | | |
− | The following is an example of a Neuron. It connects to sensory input, the hackerpspace's front and back doors, and sense data to an actuator, zirc, an actuator that writes data to #pumpingstationone on irc.freenode.net | + | The following is an example of a Neuron. It connects to sensory input, the hackerpspace's front and back doors, and sense data to an actuator, zirc, an actuator that writes data to #pumpingstationone on irc.freenode.net |
| | | |
| Before running the example, you must have a recent python, recent libzmq installed, and must have pyzmq installed. | | Before running the example, you must have a recent python, recent libzmq installed, and must have pyzmq installed. |
| | | |
− | #!/usr/bin/env python
| + | <syntaxhighlight lang="python"> |
− | import zmq
| + | #!/usr/bin/env python |
| + | import zmq |
| + | |
| + | context = zmq.Context.instance() |
| + | |
| + | # Create a zmq socket that will SUBscribe to door nodes. |
| + | door_socket = context.socket(zmq.SUB) |
| + | door_socket.connect("tcp://frontdoor.pumpingstationone.org:5556") |
| + | door_socket.connect("tcp://backdoor.pumpingstationone.org:5556") |
| + | |
| + | # The doors send a lot of types of messages. We only care about "door.state.unlock" messages |
| + | door_socket.setsockopt(zmq.SUBSCRIBE, b"door.state.unlock") |
| + | |
| + | # create a zmq socket that will PUSH data to our IRC actuator node. |
| + | zirc_socket = context.socket(zmq.PUSH) |
| + | zirc_socket.connect('tcp://sally.ad.pumpingstationone.org:5558') |
| + | |
| + | # Loop forever |
| + | while True: |
| | | |
− | context = zmq.Context.instance()
| + | # Read messages from the doors |
− |
| + | topic, message = door_socket.recv_multipart() |
− | # Create a zmq socket that will SUBscribe to door nodes. | + | |
− | door_socket = context.socket(zmq.SUB)
| + | # Send the message to the irc channel |
− | door_socket.connect("tcp://frontdoor.pumpingstationone.org:5556")
| + | zirc_socket.send(message) |
− | door_socket.connect("tcp://backdoor.pumpingstationone.org:5556")
| + | </syntaxhighlight> |
− |
| |
− | # The doors send a lot of types of messages. We only care about "door.state.unlock" messages
| |
− | door_socket.setsockopt(zmq.SUBSCRIBE, b"door.state.unlock")
| |
− |
| |
− | # create a zmq socket that will PUSH data to our IRC actuator node.
| |
− | zirc_socket = context.socket(zmq.PUSH)
| |
− | zirc_socket.connect('tcp://sally.ad.pumpingstationone.org:5558')
| |
− |
| |
− | # Loop forever
| |
− | while True:
| |
− |
| |
− | # Read messages from the doors
| |
− | topic, message = door_socket.recv_multipart()
| |
− | | |
− | # Send the message to the irc channel
| |
− | zirc.send(message)
| |
| | | |
| == Hardware == | | == Hardware == |
| | | |
− | We are targetting Beagle Bone Blacks for node hardware. While in theory, the hardware can be anything, having a consistent dev platform is useful. | + | We are targetting Beagle Bone Blacks for node hardware. While in theory, the hardware can be anything, having a consistent dev platform is useful. |
| | | |
| The BBB has 2 blocks of GPIO lines, and the capability of supporting up to 4 Serial devices. A lot of the types of data we want to collect are available over gpio and serial. | | The BBB has 2 blocks of GPIO lines, and the capability of supporting up to 4 Serial devices. A lot of the types of data we want to collect are available over gpio and serial. |
| | | |
− | ==Things Bus Broker == | + | == Things Bus Broker == |
| | | |
− | For certain types of nodes, a broker that maintains state is useful. | + | For certain types of nodes, a broker that maintains state is useful. |
| For details of this system, see https://github.com/eastein/thingsbus | | For details of this system, see https://github.com/eastein/thingsbus |
| | | |
− | == Communication == | + | == Inter-Node Communication == |
| + | |
| + | {{ambox |
| + | |type=content |
| + | |text=The code snippits contain errors |
| + | }} |
| | | |
| The software for a node can be written in any language that supports zmq and json. | | The software for a node can be written in any language that supports zmq and json. |
| | | |
| + | Nodes send messages using json data. Sensors use zmq PUB/SUB. Actuators use zmq PUSH/PULL. Neurons use whatever they have to do get the job done, which means they SUB to sensors, and PUSH to actuators. |
| + | |
| + | === Code Snippits === |
| Sensors send data like this: | | Sensors send data like this: |
| | | |
− | socket = zmq.NewSocket(zmq.PUB) | + | import zmq |
− | socket.Bind("tcp://*:5556") | + | context = zmq.Context.instance() |
− | socket.SendMessage("dot.delimited.filter", '{"json":"message"}') | + | socket = context.socket(zmq.PUB) |
| + | socket.bind('tcp://*:5556') |
| + | socket.send_multipart(('dot.delimited.filter', '{"json":"message"}')) |
| | | |
| Neurons receive data like this: | | Neurons receive data like this: |
| | | |
| + | import zmq |
| + | context = zmq.Context.instance() |
| sensor = context.socket(zmq.SUB) | | sensor = context.socket(zmq.SUB) |
| sensor.connect("tcp://sensor.tld:5556") | | sensor.connect("tcp://sensor.tld:5556") |
| + | sensor.setsockopt(zmq.SUBSCRIBE, b"dot.delimited.filter") |
| topic, message = sensor.recv_multipart() | | topic, message = sensor.recv_multipart() |
| data = json.loads(message) | | data = json.loads(message) |
Line 105: |
Line 120: |
| Neurons send data like this: | | Neurons send data like this: |
| | | |
| + | import zmq |
| + | context = zmq.Context.instance() |
| actuator = context.socket(zmq.PUSH) | | actuator = context.socket(zmq.PUSH) |
| actuator.connect('tcp://actuator.tld:5558') | | actuator.connect('tcp://actuator.tld:5558') |
Line 111: |
Line 128: |
| Actuators receive data like this: | | Actuators receive data like this: |
| | | |
| + | import zmq |
| + | context = zmq.Context.instance() |
| socket = context.socket(zmq.PULL) | | socket = context.socket(zmq.PULL) |
| socket.bind('tcp://*:5558') | | socket.bind('tcp://*:5558') |