How to send data to APM from NodeJs using mavlink? - node.js

How to write params to ArduPilot (APM) from NodeJS using node-mavlink?
For example to change geofence enable?

You should read the documentation for the mavlink parameter protocol here: http://qgroundcontrol.org/mavlink/parameter_protocol
The basic idea is that you send a PARAM_SET message to set a parameter value, then wait for an ACK in the form of a PARAM_VALUE message that has the value you just set.
The documentation for the PARAM_SET and PARAM_VALUE messages is in the mavlink defintion XML file: https://github.com/omcaree/node-mavlink/blob/c30f8a63ca6a1ebc1669fefcd07bb3780540e41b/src/mavlink/message_definitions/v1.0/common.xml#L966
Here's an (untested) example of creating and sending a PARAM_SET message to enable the geofence.
I checked the ArduCopter/APM:Copter parameter documentation to learn that the parameter you want is called FENCE_ENABLE, and that a value of 1 means it's enabled. I checked the mavlink message definition for the MAV_PARAM_TYPE enum to learn the enum value for the param_type argument to specify a UINT_8 (my best guess for the type of a boolean parameter).
myMAV.createMessage(
"PARAM_SET",
{
'target_system': 1,
'target_component': 1,
'param_id': 'FENCE_ENABLE',
'param_value': 1.0,
'param_type': 1
},
function(message) {
serialport.write(message.buffer);
});
(See the "Initialization" section of the node-mavlink documentation for information on how to load and initialize the library.)
I haven't written the code to receive the ACK from the drone, but the "Parsing Data" section of the documentation will guide you on how to do that.

I have build an node-based ground control station https://github.com/kvenux/nodegcs
Please feel free to use it.
To make the geofence enable, you need to create a message to set the related param.
Hope it helps.

Related

Using ZMQ_XPUB_MANUAL with zeromq.js

I am trying to implement a pub/sub broker with ZeroMQ where it is possible to restrict clients from subscribing to prefixes they are not allowed to subscribe to. I found a tutorial that tries to achieve a similar thing using the ZMQ_XPUB_MANUAL option. With zeromq.js it is possible to set this option:
import * as zmq from "zeromq";
// ...
const socket = new zmq.XPublisher({ manual: true });
After setting this option I am able to receive the subscription messages by calling .receive() on this socket:
const [msg] = await socket.receive();
But I have no Idea how to accept this subscription. Usally this is done by calling setSockOpt with ZMQ_SUBSCRIBE but I don't know how to do this with zeromq.js.
Is there a way to call setSockOpt with zeromq.js or is there another way to accept a subscription?
Edit
I tried user3666197's suggestion to call setSockOpt directly, but I am not sure how to do this. Rather than doing that, I took another look in the sources and found this: https://github.com/zeromq/zeromq.js/blob/master/src/native.ts#L617
It seems like setSockOpt is exposed to the TypeScript side as protected methods of the Socket class. To try this out, I created my own class that inherits XPublisher and exposed an acceptSubscription message:
class CustomPublisher extends zmq.XPublisher {
constructor(options?: zmq.SocketOptions<zmq.XPublisher>) {
super(options);
}
public acceptSubscription(subscription: string | null): void {
// ZMQ_SUBSCRIBE has a value of 6
// reference:
// https://github.com/zeromq/libzmq/blob/master/include/zmq.h#L310
this.setStringOption(6, subscription);
}
}
This works like a charm! But do not forget to strip the first byte of the subscription messages, otherwise your client won't receive any messages since the prefix won't match.
Q : "Is there a way to call setSockOpt() with zeromq.js or is there another way to accept a subscription?"
So, let me first mention Somdoron to be, out of doubts & for ages, a master of the ZeroMQ tooling.
Next comes the issue. The GitHub-sources, I was able to review atm, seem to me, that permit the ZMQ_XPUB-Socket-archetypes to process the native API ZMQ_XPUB_MANUAL settings ( re-dressed into manual-property, an idiomatic shift ), yet present no method (so far visible for me) to actually permit user to meet the native API explicit protocol of:
ZMQ_XPUB_MANUAL: change the subscription handling to manual...with manual mode subscription requests are not added to the subscription list. To add subscription the user need to call setsockopt() with ZMQ_SUBSCRIBE on XPUB socket./__ from ZeroMQ native API v.4.3.2 documentation __/
Trying to blind-call the Socket-inherited .SetSockOpt() method may prove me wrong, yet if successful, it may be a way to inject the { ZMQ_SUBSCRIBE | ZMQ_UNSUBSCRIBE } subscription-management steps into the XPUB-instance currently having been switched into the ZMQ_XPUB_MANUAL-mode.
Please test it, and if it fails to work via this super-class inherited method, the shortest remedy would be to claim that collision/conceptual-shortcomings directly to the zeromq.js maintainers ( it might be a W.I.P. item, deeper in their actual v6+ refactoring backlog, so my fingers are crossed for either case ).

receive SMS using python and python-smpp

I'm a newbie in SMPP but I need to simulate traffic over the SMPP protocol. I have found the tutorial how to send SMS using smpp lib from Python How to Send SMS using SMPP Protocol
I'm trying to write a receiver,but I am unable to get it to work. Please help.
My code is:
import smpplib
class ClientCl():
client=None
def receive_SMS(self):
client=smpplib.client.Client('localhost',1000)
try:
client.connect()
client.bind_receiver("sysID","login","password")
sms=client.get_message()
print(sms)
except :
print("boom! nothing works")
pass
sms_getter=ClientCl.receive_SMS
From what I can understand the smpplib you are using is the one available at github. Looking at your code and the client code, I can't find the function client.get_message. Perhaps you have an older version of the library? Or I have the wrong library. In any case, it is likely that the get_message function does not block and wait for the message to arrive.
Looking at the client code it seems that you have two options:
Poll the library until you get a valid message
Setup the library to listen to the SMPP port and call a function once a message arrives.
If you look at the README.md file it shows how you can setup the library to implement the second option (which is the better option).
...
client = smpplib.client.Client('example.com', SOMEPORTNUMBER)
# Print when obtain message_id
client.set_message_sent_handler(
lambda pdu: sys.stdout.write('sent {} {}\n'.format(pdu.sequence, pdu.message_id)))
client.set_message_received_handler(
lambda pdu: sys.stdout.write('delivered {}\n'.format(pdu.receipted_message_id)))
client.connect()
client.bind_transceiver(system_id='login', password='secret')
for part in parts:
pdu = client.send_message(
source_addr_ton=smpplib.consts.SMPP_TON_INTL,
#source_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure it is a byte string, not unicode:
source_addr='SENDERPHONENUM',
dest_addr_ton=smpplib.consts.SMPP_TON_INTL,
#dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure thease two params are byte strings, not unicode:
destination_addr='PHONENUMBER',
short_message=part,
data_coding=encoding_flag,
esm_class=msg_type_flag,
registered_delivery=True,
)
print(pdu.sequence)
client.listen()
...
When receiving a message or delivery receipt the function defined in client.set_message_received_handler() will be called. In the example, it is a lambda function. There is also an example on how to set up for listening in a thread.
If you prefer the simpler polling option you should use the poll function. For the simplest implementation all you need to do is:
while True:
client.Poll()
As before, the function set in client.set_message_received_handler() will be called once a message arrives.

ONVIF PullMessages Fault

I understand that cameras that do not have WSBaseNotification feature do not support push-style notifications (Notify), so I have to do the pull-style way (CreatePullPointSubscription and PullMessages).
First I obtain the SubscriptionReference address from CreatePullPointSubscription and pass it to the "To" address in PullMessages. This has succeeded with one of the three cameras I have tested but failed with the other.
Here is a sample of response for CreatePullPointSubscription:
<SOAP-ENV:Header><wsa5:MessageID>urn:uuid:18764990-3fd8-4175-b074-bfdd6816d5a2</
wsa5:MessageID><wsa5:RelatesTo>urn:uuid:1adbe268-c822-eb58-8560-b07639671351</wsa5:RelatesTo><wsa5:To SOAP-
ENV:mustUnderstand="true">http://www.w3.org/2005/08/addressing/anonymous</wsa5:To><wsa5:Action SOAP-
ENV:mustUnderstand="true">http://www.onvif.org/ver10/events/wsdl/EventPortType/
CreatePullPointSubscriptionResponse</wsa5:Action></SOAP-ENV:Header><SOAP-
ENV:Body><tev:CreatePullPointSubscriptionResponse><tev:SubscriptionReference><wsa5:Address>http://172.22.22.35:80/
onvif/device_service?Idx=0</wsa5:Address></tev:SubscriptionReference><wsnt:CurrentTime>2015-11-26T17:05:55Z</
wsnt:CurrentTime><wsnt:TerminationTime>2038-01-19T03:14:07Z</wsnt:TerminationTime></
tev:CreatePullPointSubscriptionResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
And PulMessagesRequest:
<s:Header><wsa:To>http://172.22.22.35:80/onvi /device_service?Idx=0</wsa:To><wsse:Security><wsse:UsernameToken>
<wsse:Username>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-
profile-1.0#PasswordDigest">XWhDcuw3cztspGCLlpQfVaqM1mU=</wsse:Password><wsse:Nonce>NTY1NmNiODFjYTk4MWZlNjFmNDA=</wsse:Nonce>
<wsu:Created>2015-11-26T09:06:09Z</wsu:Created></wsse:UsernameToken></wsse:Security></s:Header><s:Body><tev:PullMessages>
<tev:Timeout>PT5S</tev:Timeout><tev:MessageLimit>2</tev:MessageLimit></tev:PullMessages></s:Body></s:Envelope>
And PullMessagesResponse:
<SOAP-ENV:Header><wsa5:To SOAP-ENV:mustUnderstand="true">http://172.22.22.35:80/onvif
/device_service?Idx=0</wsa5:To></SOAP-ENV:Header><SOAP-ENV:Body><SOAP-ENV:Fault><SOAP-ENV:Code><SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
<SOAP-ENV:Subcode><SOAP-ENV:Value>InvalidArgVal</SOAP-ENV:Value></SOAP-ENV:Subcode></SOAP-ENV:Code><SOAP-ENV:Reason><SOAP-ENV:Text
xml:lang="en">InvalidArgVal</SOAP-ENV:Text></SOAP-ENV:Reason><SOAP-
ENV:Detail>There is no subscribe.</SOAP-ENV:Detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
From the ONVIF core specs:
9.1.2 Pull messages
The device shall provide the following PullMessages command for all SubscriptionManager endpoints returned by the CreatePullPointSubscription command.
Therefore you need to pull the messages from the address returned int the CreatePullPointSubscription . Populating the wsa5:To field in the body of the request but using the URL of the event service is in general not enough.
You posted only the body of the soap requests and not the head, thus it's impossible to check the URL you're using.

Post a text request in Casablanca (C++ REST SDK)

I am writing a client side code in Visual C++ 2012 using C++ Rest SDK (codename "Casablanca").
I have a client created and wish to POST a text string to the server. However, when I send the following code, it is compiling but not sending sending the request.
When I remove everything after "methods::POST" and send a blank post request, then it is sent and received by the server.
Can you please guide me where the problem is. The documentation related to this function is available on Casablanca Documentation.
pplx::task<http_response>resp = client.request(methods::POST,L"",L"This is the random text that I wish to send", L"text/plain");
I think the usage you give here looks correct.
Is your Casablanca the latest version ? Please check that out from here : http://casablanca.codeplex.com/
If you are sure your measurement is accurate, you may want to create a minimal repro and file a bug here : http://casablanca.codeplex.com/workitem/list/basic
I was having a similar problem, all my POSTs was arriving in blank on server , after a few hours work above it, i found a possible solution.
I changed the default content type to application/x-www-form-urlencoded and I started to pass the values like this Example data=text1&data2=text2
client.request(methods::POST,L"",L"data=text1&data2=text2", L"application/x-www-form-urlencoded");
The body parameter must be a json::value.
I cannot comment yet so I have to put my thoughts in an answer. I solved this problem like this: There is an overload of the request method that takes as a parameter the content type so that you do not have to change the code.
m_client->request(methods::POST, L"/statuses/update.json?" + url_encode(data),L"",L"application/x-www-form-urlencoded");
Obviously you would have to implement the url_encode method but that is not difficult. There is a pretty good implementation in "Cassablanca". A search on this site will alos turn up some good examples.

Netty: Pipe-ing output of one Channel to the input of an other

Netty-Gurus,
I've been wondering if there is a shortcut/Netty-Utility/smart-trick
for connecting the input of one Channel to the output of
an other channel. In more details consider the following:
Set-Up a Netty (http) server
For an incoming MessageEvent get its ChannelBuffer
and pipe its input to a NettyClient-ChannelBuffer
(which is to be set up along the lines of the NettyServer).
I'm interested in how to achieve bullet-point 3. since my first
thoughts along the lines
// mock messageReceived(ChannelHandlerContext ctx, MessageEvent e):
ChannelBuffer bufIn = (ChannelBuffer) e.getMessage();
ChannelBuffer bufOut = getClientChannelBuffer();// Set-up somewhere else
bufOut.write(bufIn);
seem to me awkward because
A. I have to determine for each and every messageReceived-Event
the target ChannelBuffer
B. To much Low-Level tinkering
My wish/vision would be to connect
--> the input of one Channel
--> to the output of an other channel
and let them do their I/O without any additional coding.
Many thanks in advance!,
Traude
P.S: Issue has arisen as I'm trying to dispatch the various HTTP-requests to the
server (one entry point) to several other servers, depending on
the input content (mapping based on the first HTTP request line).
Obviously, I also need to do the inverse trick -- pipeing back client
to server -- but I guess it'll be similar to the solution of
the question before.
Looks like you need to use a multiplexer in you business handler. The business handler could have a map. With key as "first http request line" and value as the output channel for the server. Once you do a lookup you just do a channel.write(channelBuffer);
Also take a look at bruno de carvalho's tcp tunnel, which may give you more ideas on how to deal with these kind of requirements.

Resources