Using Bluemix. Using NodeMCU MQTT Lua. Get the following message about topic is not valid. How to debug?
Closed connection from 108.67.152.187. [The topic is not valid.] [6] times in the last [5] minutes
Token auth succeeded: ClientID='myClientID'
NodeMCU Lua code:
t1=123 -- arbitrary value
topic = "iotsensor.fake"
m:publish(topic ,'{"d": {"data":'..t1..'}}', 0, 0,
function(conn)
-- Print confirmation of data published
print("Sent message #"..count.." data:"..t1)
end)
For IoT Foundation:
Publishing events topic iot-2/evt/event_id/fmt/format_string
Subscribing to commands topic iot-2/cmd/command_id/fmt/format_string
Refer to the documentation for more details.
Related
I borrowed code from Toms Hardware on how to use MQTT and subscribe. JRMI is the publisher of the messages and it keeps repeating them over and over again. Is there anyway to have the message sent only once? I dont have this problem when I subscribe to MQTT via http://www.hivemq.com/demos/websocket-client/ The MQTT service I'm using is broker.hivemq.com
For those not familiar with JRMI, it is the JAVA program that model railroads use to control tracks,lighting, DCC etc. Ref: https://www.jmri.org/
The link to Tom's is here https://www.tomshardware.com/how-to/send-and-receive-data-raspberry-pi-pico-w-mqtt
The code adapted from Tom's is
import network
import time
from machine import Pin
from umqtt.simple import MQTTClient
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("whatever","pwd")
time.sleep(5)
print(wlan.isconnected())
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_sub = b'/trains/track/turnout/#'
def sub_cb(topic, msg):
print("New message on topic {}".format(topic.decode('utf-8')))
msg = msg.decode('utf-8')
print(msg)
def mqtt_connect():
client = MQTTClient(client_id, mqtt_server, keepalive=60)
client.set_callback(sub_cb)
client.connect()
print('Connected to %s MQTT Broker'%(mqtt_server))
return client
def reconnect():
print('Failed to connect to MQTT Broker. Reconnecting...')
time.sleep(5)
machine.reset()
try:
client = mqtt_connect()
except OSError as e:
reconnect()
while True:
client.subscribe(topic_sub)
time.sleep(1)
The setup inside JRMI for MQTT (edit->preferences) is as follows:
JMRI, by default, publishes with "the retain option on". When you subscribe to a topic the broker will send you the most recent (if any) retained message. This occurs even if you already had an identical subscription as per the MQTT Spec:
If a Server receives a SUBSCRIBE Packet containing a Topic Filter that is identical to an existing Subscription’s Topic Filter then it MUST completely replace that existing Subscription with a new Subscription. The Topic Filter in the new Subscription will be identical to that in the previous Subscription, although its maximum QoS value could be different. Any existing retained messages matching the Topic Filter MUST be re-sent, but the flow of publications MUST NOT be interrupted [MQTT-3.8.4-3].
In your code you are calling Subscribe in a loop:
while True:
client.subscribe(topic_sub)
time.sleep(1)
To avoid the repeated messages move the subscribe out of the loop (you only need to subscribe once!). Something like the following (simplified!) code:
client = mqtt_connect()
client.subscribe(topic_sub)
while True:
client.wait_msg() // Use client.check_msg() if you have other stuff to do
I am looking to retrieve some Solace queue stats e.g. the current messages spooled count out of the maximum limit for us to set a threshold to stop publishing more messages to the queue.
Also, to subscribe to vpn events to track message discard rates.
By the time we receive errors e.g. MaxMsgUsageExceeded/SpoolOverQuota, it will be too late.
I can't seem to find any of these on SolaceSystems.Solclient.Messaging API
https://docs.solace.com/API-Developer-Online-Ref-Documentation/net/html/7f10bcf6-19f4-beff-0768-ced843e35168.htm
Would be great if someone could help
(using C# for this)
To poll for Solace queue stats from your C# application, you could use legacy SEMP over the message bus to make a SEMP request for the details that you want. Semp (Solace Element Management Protocol) is a request/reply protocol that uses an XML schema to identify all managed objects available in a message broker. Applications can use SEMP to manage and monitor a message broker.
To allow for legacy SEMP to be used over the message bus, as opposed to the management interface, it first needs to be enabled on the Solace PubSub+ message broker at the VPN level.
To publish a SEMP request with the Solace .Net Messaging API, perform the following steps:
Create a Session.
Create the message topic. “#SEMP//SHOW”
ITopic topic = ContextFactory.Instance.CreateTopic( “#SEMP/<router name>/SHOW”);
Create a request message and set its Destination to the topic in Step 2:
IMessage requestMsg = ContextFactory.Instance.CreateMessage();
requestMsg.Destination = topic;
Set the SEMP request string as the binary attachment.
string SOLTR_VERSION = "8_4_0" //change to the message-broker's version
string SEMP_SHOW_QUEUE = "<rpc semp-version=\"soltr/" + SOLTR_VERSION +
"<show><queue><name>queueName</name><detail></detail></queue></show></rpc>";
requestMsg.BinaryAttachment = Encoding.UTF8.GetBytes(SEMP_SHOW_QUEUE);
Call the SendRequest(…) method on Session.
IMessage replyMsg;
ReturnCode rc = session.SendRequest(requestMsg, out replyMsg, timeout);
The SEMP response is returned in replyMsg.
Obtain the binary attachment data from the reply message:
replyMsg.BinaryAttachment
The binary attachment contains the SEMP reply for the command topic in the publish request.
The Solace PubSub+ message broker does raise an event when an egress message is discarded. However, it is only sent out approximately once every 60 seconds for the specified client so it is not possible to get these exact rates.
It is possible for your .NET application to subscribe to VPN-level events over the message-bus. To do this, you must first enable the Solace PubSub+ message broker to publish the events. You can then subscribe to the special topic and receive the events as messages.
The topic to subscribe to is:
#LOG/<level>/VPN/<routerName>/<eventName>/<vpnName>
The different levels can use the * wildcard. For example, if you wish to subscribe to all VPN events of all levels for the VPN apple on router QA-NY1, the topic string would be:
#LOG/*/VPN/QA-NY1/*/apple
SEMP (starting in v2) is a RESTful API for configuring, monitoring, and administering a Solace PubSub+ broker.
1-The swapper page link is SEMP V2 API
2-The Swagger metadata definitions URL is located # http://{solace-sever-url}/SEMP/v2/config/spec
3- From Visual studio, add REST API Client
4-In the configuration dialog pass swagger metadata URL (defined at step 2), for code purpose I choose SolaceSemp as input value parameter for client namespace input.
4 Once you click ok, VS will create the client along with the models under SolaceSemp namespace
5 Start using the client as per following
using SolaceSemp;
using Microsoft.Rest;
var credentials = new BasicAuthenticationCredentials();
credentials.UserName = "place user name";
credentials.Password = "place password";
using (var client = new SolaceSempClient(credentials))
{
var model = client.GetAboutApi();
}
The documentation for mqtt.client:connect() states that the last arg is a "callback function for when the connection could not be established".
I have a case where mqtt.client:connect() succeeds, so the "not established" callback is not called (correct behavior). But, later, when my mqtt broker goes down, the "not established" callback function gets unexpectedly activated.
I have the following code:
function handle_mqtt_error (client, reason)
print("mqtt connect failed, reason = "..reason..". Trying again shortly.")
tmr.create():alarm(10 * 1000, tmr.ALARM_SINGLE, do_mqtt_connect)
end
function do_mqtt_connect ()
print("connecting---")
m:connect(MQTT_HOST, MQTT_PORT, 1, function(client)
print("mqtt connected")
client:publish("topic/status", "online", 1, 1)
end,
handle_mqtt_error
)
print("returning---")
end
-- init mqtt client
m = mqtt.Client(MQTT_CLIENT_ID, 120, MQTT_USER, MQTT_PASS)
-- connect to mqtt
print("Starting Test")
do_mqtt_connect()
I see the output from the test begin, as expected, with:
Starting Test
connecting---
returning---
mqtt connected
At this point, I kill my mqtt broker, and I unexpectedly see:
mqtt connect failed, reason = -5. Trying again shortly.
connecting---
returning---
mqtt connect failed, reason = -5. Trying again shortly.
connecting---
returning---
And, happily, but unexpectedly, when I restart my broker, I see:
mqtt connected
So, it appears that handle_mqtt_error() is not only called "when the connection could not be established". It appears that it also be called if mqtt.client:connect() successfully establishes a connection, then the connection is later broken.
======= New Information =======
I downloaded the "dev" tree and used the Docker image to build the firmware. Within mqtt.c, I enabled NODE_DBG. The interesting lines are:
enter mqtt_socket_reconnected.
mqtt connect failed, reason = -5. Trying again shortly.
enter mqtt_socket_disconnected.
leave mqtt_socket_disconnected.
leave mqtt_socket_reconnected.
The "mqtt connect failed..." message is printed by handle_mqtt_error(), which is my "connect failed" callback.
Here's my theory. When my test starts, do_mqtt_connect() calls mqtt_socket_connect(), which does this:
espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected);
This sets reconnect_callback (in app/lwip/app/espconn.c). Later, after my broker goes down and comes back up, espconn_tcp_reconnect() is called (in app/lwip/app/espconn_tcp.c). It calls the reconnect_callback, which is mqtt_socket_reconnected(), which calls handle_mqtt_error().
So, I think the end result doesn't match the documentation, but it works out okay for me. If the behavior did match the documentation, I would just add some Lua code to handle the "offline" event, and try to reestablish the mqtt connection. I just thought someone might be interested if the behavior doesn't match the documentation.
My web application is failing to gather WebRTC relay ICE candidates via a CoTURN server when using Safari 11 on iOS 11 (iPhone 5s & iPhone 7) or desktop. The web application (which establishes a one-way audio only WebRTC peer connection) works fine between the real browsers (Chrome and Firefox) either direct or via CoTURN relay, and I normally get 6-15 ICE candidates on these browsers.
I have a (frankly, unnecessary) call to getUserMedia on the receiving side, which allows host ICE candidates to be produced by Safari. (Note... the user must approve audio and/or video access before Safari will provide host Ice Candidates, even if on a receiving-only end. I'm past that hurdle, but just so you won't hit it too... This is out of "privacy" concerns.). Before I added the allow getUserMedia, I received no ICE. Now I receive two candidates. One with a private IPv4 and another with an IPv6. This is enough to get the app working properly when on the same machine or local network. So I'm pretty confident with other parts of the application code. I am not sure if my problem is with the application code or the CoTURN server.
Example of the ICE candidates received:
{"candidate":{"candidate":"candidate:622522263 1 udp 2113937151 172.27.0.65 56182 typ host generation 0 ufrag r23H network-cost 50","sdpMid":"audio","sdpMLineIndex":0,"usernameFragment":"r23H"}}
I pretty sure the RTCIceServer Dictionary for my RTCPeerConnection is inline with the following standards:
https://w3c.github.io/webrtc-pc/webrtc.html
https://www.rfc-editor.org/rfc/rfc7064
https://www.rfc-editor.org/rfc/rfc7065
And I've tried multiple variations of parameters:
// For Example:
var RPCconfig = {
iceServers: [{
urls: "turn:Example.live",
username: "un",
credential: "pw"
}]
};
// Or:
var RPCconfig = {
iceServers: [{
urls: "turns:Example.live",
username: "un",
credential: "pw",
credentialType: "password"
}, {
urls: "stun:Example.live"
}]
};
// And even more desperate attempts...
var RPCconfig = {
iceServers: [{
urls: "turn:Example.live?transport=tcp",
username: "un",
credential: "pw",
credentialType: "password"
}]
};
Here's an example of the signaling process log for an idea of what is going on. This is from the receiving side, which is Safari 11. The other browser was Chrome (compare 6 vs 2 ICE candidates). The state change refers to oniceconnectionstatechange.
SDP Offer received.
Sending signal SDP
Sending signal IceCandidate
Sending signal IceCandidate
ICE Candidate Received
4:08:25 AM State Change -> checking
ICE Candidate Received
ICE Candidate Received
ICE Candidate Received
ICE Candidate Received
ICE Candidate Received
4:08:40 AM State Change -> failed
CoTURN is configured quite liberally in terms of accepting every possible transport method as far as I am aware. It works well for providing ICE Candidates and as a relay for the other browsers.
Any direction would be greatly appreciated. Even if it is just a sample RTCIceServer Dictionary code that works or a proven TURN server to try.
From what I read in MQTT protocol message payload, it doesn't seem to support telling who is the publisher on a published message. But is it possible that a MQTT subscriber to know which publisher the message are from?
A 'msg.publisher' workaround maybe?
#!/usr/bin/env python
import mosquitto
def on_message(mosq, obj, msg):
print "Publisher: %s, Topic: %s, "Msg: %s" % (msg.publisher, msg.topic, msg.payload)
cli = mosquitto.Mosquitto()
cli.on_message = on_message
cli.connect("127.0.0.1", 1883, 60)
cli.subscribe("dns/all", 0)
cli.subscribe("nagios/#", 0)
while cli.loop() == 0:
pass
You're right, the MQTT specification has no field in the PUBLISH packet to specify which publisher a certain message comes from.
I can think of two possible "work-around" implementations:
1) Add the publisher information in the payload of the message. Application level parsing would allow you to retrieve the publisher ID from the message payload.
2) Add the publisher information in the topic. You could concoct a clever topic hierarchy with a level dedicated to the publisher.
For example: data/
Your subscriber could then subscribe to data/+ and parse the last level to retrieve the publisher ID.