Closed roullli closed 3 years ago
You need to connect to Hono's north bound Command & Control API. If you have installed Hono using the Helm chart, then the north bound C&C API is exposed by the Dispatch Router service. You cannot send a command to a device by means of any of the protocol adapters.
Thanks for your reply.
is there any example Python code (or anything else) for sending commands?
I want to see whats the problem with my code. since it connects to the AMQP network but the MQTT client can not receive the command.
I used command/rover
address to send command for my device(rover2) in tenant "rover" which is subscribed to command/+/+/req/#
.
This is the response from the sender code:
you need to also set the address and other properties in the command message. See https://www.eclipse.org/hono/docs/api/command-and-control/ for details...
There is no python code, but you can take a look at https://github.com/eclipse/hono/blob/master/client/src/main/java/org/eclipse/hono/client/impl/CommandClientImpl.java for a Java based implementation ...
I tried to fix the msg format which is sending by the code. The message goes reaches Hono but it seems that AMQP Network rejects the msg. I sniffed the packets and here is the result: How can I find what is wrong with the msg? Is it somewhere in documentation?
Can you post the code that you use for sending the command?
import Tkinter as tkinter
import proton
from cli_proton_python import sender
import ssl
import uuid
from proton._reactor import _generate_uuid
#imports end
# Receive commands without TLS via MQTT
# mosquitto_sub -v -h 192.168.1.152 -u rover2@rover -P rover-secret -t command/+/+/req/#
#const
scheme = "amqp://"
username = "consumer@HONO"
password = "verysecret"
hostAndPort = "192.168.1.154:15672"
tenant = "rover"
device = "rover2"
topic_to_publish = "command/"+tenant
speed = 380
#const end
def sendControlMsg( msg ):
print ("sending control msg " + str(msg))
parser = sender.options.SenderOptions()
opts, _= parser.parse_args()
opts.broker_url = scheme + username + ":" + password +"@"+ hostAndPort +"/"+ topic_to_publish
opts.msg_id = "0" # will be generated automatically
opts.msg_subject = "RoverDriving"
opts.msg_content = str(msg)
opts.msg_reply_to = "command_response/"+tenant+"/"+str(_generate_uuid())
opts.msg_correlation_id = "null"
opts.msg_content_type = "application/json"
opts.msg_address = "command/"+tenant+"/"+device
container = proton.reactor.Container(sender.Send(opts))
container.run()
#funcs
def turn_right():
sendControlMsg( "{\"command\":\"E\",\"speed\":"+ str(speed_var.get() + 360) +" }" )
print("turn right clicked")
def turn_right_back():
sendControlMsg( "{\"command\":\"D\",\"speed\": "+ str(speed_var.get() + 360) +" }" )
print("turn right back clicked")
def turn_left():
sendControlMsg("{\"command\":\"Q\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("turn left clicked")
def turn_left_back():
sendControlMsg("{\"command\":\"A\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("turn left back clicked")
def move_forward():
sendControlMsg("{\"command\":\"W\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("move forward clicked")
def move_back():
sendControlMsg("{\"command\":\"S\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("move back clicked")
def spot_right():
sendControlMsg("{\"command\":\"K\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("move spot right clicked")
def spot_left():
sendControlMsg("{\"command\":\"J\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("move spot left clicked")
def stop_move():
sendControlMsg("{\"command\":\"F\",\"speed\": "+ str(speed_var.get() + 360) +" }")
print("Stop clicked")
def set_speed(event):
speed = speed_var.get() + 360
print("set speed to", speed)
def showPosEvent(event):
print("posevt")
def onArrowUp(event):
move_forward()
print("Arrow up")
def onArrowDown(event):
move_back()
print("Arrow down")
def onArrowLeft(event):
turn_left()
print("Arrow left")
def onArrowRight(event):
turn_right()
print("Arrow right")
def onSpaceBar(event):
stop_move()
print("Spacebar pressed")
if __name__=="__main__":
tkroot = tkinter.Tk()
tkroot.title("Rover Controller")
speed_var = tkinter.DoubleVar() #tkinter.DoubleVar()
labelfont = ('arial', 15, 'bold')
#Keyboard Input
tkroot.bind('<Up>',onArrowUp)
tkroot.bind('<Down>',onArrowDown)
tkroot.bind('<Left>',onArrowLeft)
tkroot.bind('<Right>',onArrowRight)
tkroot.bind('<space>',onSpaceBar)
tkroot.focus()
#Keyboard Input End
#Buttons
B_right = tkinter.Button(tkroot, text =">" , command= turn_right)
B_right.place(x = 65, y= 25, height=25, width=25)
B_right_back = tkinter.Button(tkroot, text =">" , command= turn_right_back)
B_right_back.place(x = 65, y= 55, height=25, width=25)
B_left = tkinter.Button(tkroot, text ="<", command= turn_left)
B_left.place(x= 15,y = 25, height=25, width=25)
B_left_back = tkinter.Button(tkroot, text ="<", command= turn_left_back)
B_left_back.place(x= 15,y = 55, height=25, width=25)
B_up = tkinter.Button(tkroot, text ="^", command= move_forward)
B_up.place(x= 40, y = 10 , height=25, width=25)
B_down = tkinter.Button(tkroot, text ="v", command= move_back)
B_down.place(x= 40, y = 70, height=25, width=25)
B_stop = tkinter.Button(tkroot, text ="Stop", command= stop_move)
B_stop.place(x = 10,y = 160 , height = 30, width=85)
B_spot_left = tkinter.Button(tkroot, text ="<)", command= spot_left)
B_spot_left.place(x = 100,y = 160 , height = 30, width=35)
B_spot_right = tkinter.Button(tkroot, text =">(", command= spot_right)
B_spot_right.place(x = 140,y = 160 , height = 30, width=35)
speed_label = tkinter.Label(tkroot , text = "Speed")
speed_label.place(x= 10, y = 105, height=50, width=50)
speed_scale = tkinter.Scale(tkroot, variable = speed_var,orient = tkinter.HORIZONTAL)
speed_scale.bind("<ButtonRelease-1>", set_speed)
speed_scale.place(x= 60, y = 105, height=50, width=85)
#Buttons end
tkroot.mainloop()
The code looks good. There is one thing that might cause the problem, however. I am no expert in Python, but the line
opts.msg_content = str(msg)
suggests to me that the JSON payload is being added to the message as a an AMQP Value section instead of a Data section, as required by Hono's Command & Control API. You will need to check with the Python library that you are using for sending the AQMP message. Which is it? And BTW, which version of Hono are you using?
I'm using Qpid Proton library to send AMQP message: http://qpid.apache.org/releases/qpid-proton-0.32.0/proton/python/docs/overview.html I used Helm Chart to deploy Hono and currently, I'm using the latest version (1.4)
You might want to try to set the message body as bytes instead of a string. However, I have no clue how this works in Python ...
@roullli have you been able to send a command using your Python client?
Unfortunately not! still working on it!
I have posted an answer to your question on stackoverflow. Hope that helps with getting it working ...
Great, Thanks! So I'll close this issue and follow the discussion over there.
Hi,
I am trying to control a rover by Hono's Command and Control functionality. I have created a Python code which subscribes to
command/+/+/req/#
topic successfully import tkinter import paho.mqtt.client as mqttand I tested it with Hono Command Line Client, which also was successful.
java -jar hono-cli-1.3.0-exec.jar --hono.client.host=192.168.1.154 --hono.client.port=15672 --hono.client.username=consumer@HONO --hono.client.password=verysecret --tenant.id=rover --device.id=rover2 --spring.profiles.active=command
But know I am trying to send commands through another python code which uses Proton library to directly send commands through AMQP broker to the device. it seems it is not able to create the link or deliver the message. here is the code :
First of all, am I doing it in the right way? is it possible to send commands directly through the AMQP adapter or it should be going only through the dispatch router? If the answer is yes? what is wrong with my code? do I need any kind of certificate?
Thanks in advance.