I am trying to connect to Google's MQTT server but I am getting errors
I created all the certificates and registered my device (Adafruit huzzah32)
and the documentation says you connect to mqtt.googleapis.com:8883
So I do
WiFiClientSecure wifi;
MQTTClient client;
client.begin("mqtt.googleapis.com", 8883, wifi);
When I try to connect I use the device path
const char* jwt = "{json web token}";
const char* device = "projects/{project-id}/locations/{cloud-region}/registries/{registry-id}/devices/{device-id}";
Serial.print("Connecting to mqtt");
while (!client.connect(device,"unused",jwt)) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.println("Connected to mqtt");
but it never connects
I verified the google certificate by calling
openssl s_client -showcerts -connect mqtt.googleapis.com:8883
and I put in my RSA Private key and certificate key that was made
wifi.setCACert(googleCertificate2);
wifi.setCertificate(myCertificate);
wifi.setPrivateKey(privateCert);
What am I doing wrong?
Here is the connection documentation
https://cloud.google.com/iot/docs/how-tos/mqtt-bridge
Update
I made a quick java example to see if I can connect going off the example they have for connecting and I get a MqttException saying Bad user name or password (4)
Here is the code for that
private void doStuff(){
String clientId = String.format("ssl://%s:%s", "mqtt.googleapis.com", 8883);
String mqttClientId = String.format("projects/%s/locations/%s/registries/%s/devices/%s","{project_id}", "us-central1", "{register}", "{device}");
MqttConnectOptions connectOptions = new MqttConnectOptions();
connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
Properties sslProps = new Properties();
sslProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
connectOptions.setSSLProperties(sslProps);
connectOptions.setUserName("unused");
try{
String jwt = createJwtRsa("{project-id}");
connectOptions.setPassword(jwt.toCharArray());
MqttClient client = new MqttClient(clientId, mqttClientId, new MemoryPersistence());
while(!client.isConnected()){
try{
client.connect(connectOptions);
}catch (MqttException e) {
e.printStackTrace();
}
}
Log.d("","");
}catch (Exception e){
e.printStackTrace();
}
}
private String createJwtRsa(String projectId) throws Exception {
DateTime now = new DateTime();
JwtBuilder jwtBuilder =
Jwts.builder().setIssuedAt(now.toDate()).setExpiration(now.plusDays(1000000).toDate()).setAudience(projectId);
byte[] keyBytes = readBytes(getAssets().open("rsa_private_pkcs8"));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey k = kf.generatePrivate(spec);
return jwtBuilder.signWith(SignatureAlgorithm.RS256, k).compact();
}
As you can see here I have the IoT service acount added to IAM
Does that mean my keys that I generated with openssl are incorrect?
My problem ended up being that I was trying to set a really large expiration date on my Json Web Token (on purpose so I didnt have to keep generating new ones since I have not found a way to do that in arduino) and it looks like that google's mqtt server does not accept anything over a day so the keys will have to be updated daily.
Also inorder to connect to the MQTT server I had to change the buffer size of the MqttClient on the arduino to have a buffer size of 1024 bytes.
MQTTClient client(1024);
anything less I would get an error saying buffer isnt big enough.
here the IAM roles are being explained ...the paragraph here sounds alike what you describe:
On the IAM page in Google Cloud Platform Console, verify that the role Cloud IoT Core Service Agent appears in the Members list for the relevant project service account. (Look for the project service account that ends in #gcp-sa-cloudiot.iam.gserviceaccount.com.)
If the Cloud IoT Core Service Agent role does not appear in the Members list, use gcloud to add the cloudiot.serviceAgent role to the relevant project service account. This role includes permission to publish to Pub/Sub topics.
if not yet having installed it, the Cloud SDK is required for all those gcloud CLI commands, which can be used to list & edit the configurations (of which all can be done through the console, as well)... it's maybe easier, because all of the examples there use it, too.
update ...
concerning JWT refresh tokens, see this article or have some Q & A or the specification: JSON Web Token (JWT), JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants.
here's another relevant article: https://medium.com/google-cloud/refreshing-json-web-tokens-jwts-for-google-cloud-iot-core-897318df3836
Related
I have a problem here with the dynamic TCP connection approach (Spring-IP Dynamic FTP Sample). When a message is received, I want to get the TCP connection details for the received message. this way I can keep track in my application of the sender sending that message. But in Service activator I am not able to get this detail.
Also need the connection details when my TCP client is connected to the server. This way if the server wants to initiate the communication, it will have the connection details.
For info my application has more than one TCP clients and servers.
Got an answer reply in another post from Mr. Gary Russell.
Answer
For normal request/reply processing, using an inbound gateway, the framework will take care of routing the service activator reply to the correct socket. It does this by using the connection id header.
If you need to provide arbitrary replies (e.g. more than one reply for a message, you have to use inbound and outbound channel adapters and your application is responsible for setting up the connection id header.
There are two ways to access the required header in a POJO invoked by a service activator:
public void foo(byte[] payload, #Header(IpHeaders.CONNECTION_ID) String connectionId) {
...
}
public void foo(Message<byte[]> message) {
String connectionId = message.getHeaders().get(...);
}
Then, when you send your replies, you need to set that header somehow.
EDIT
Below Is My Implementation
To get all the connected clients simply get the ServerConnectionFactory from the context and access the method .getConnectedClients(). It returns the list connectionIds for each connected client.
AbstractServerConnectionFactory connFactory = (AbstractServerConnectionFactory) appContext.getBean("server");
List<String> openConns = connFactory.getOpenConnectionIds();
As mentioned above in Gary's response, use this connectionId and set it in conneciton header while sending the message to a client. Sample code as follows.
MessageChannel serverOutAdapter = null;
try{
serverOutAdapter = (MessageChannel) appContext.getBean("toObAdapter");
}catch(Exception ex){
LOGGER.error(ex.getMessage());
throw ex;
}
if(null == serverOutAdapter){
throw new Exception("output channel not available");
}
AbstractServerConnectionFactory connFactory = (AbstractServerConnectionFactory) appContext.getBean("serverConnFactoryBeanId");
List<String> openConns = connFactory.getOpenConnectionIds();
if(null == openConns || openConns.size() == 0){
throw new Exception("No Client connection registered");
}
for (String connId: openConns) {
MessageBuilder<String> mb = MessageBuilder.withPayload(message).setHeader(IpHeaders.CONNECTION_ID, connId);
serverOutAdapter.send(mb.build());
}
Note 1: If u want to send messages from the server then be cautious to configure the server and client connection factories in a way that they do not time-out. i.e put so-keep-alive = true in client connection factory.
Note 2: If the server has to communicate with the client then make sure that the client connects to the server as soon as the context is loaded. Because Spring-IP client connection factory connects only when the first message is sent out. In order to connect client after context load, put client-mode="true" in tcp client context for the "tcp-outbound-channel-adapter".
We are trying to run the sample app for push notifications with some modification to get it to send out a broadcast notification, but it is not getting sent.
We have modified the PushBackendEmulator code as well. The emulator invokes the submitBroadCastNotification procedure successfully and the following result is returned:
Server response :: /-secure-{"result":"Notification sent to all
users","isSuccessful":true}/
However, it appears the WL.Server.sendMessage method is not sending the message and returns. I am not able to see the server side logs either after a thorough search on the liberty server except for the messages.log on the liberty server which shows the following when WL.Server.sendMessage is called.
ht.integration.js.JavaScriptIntegrationLibraryImplementation E
FWLSE0227E: Failed to send notification. Reason: FPWSE0009E: Internal
server error. No devices found [project worklight]
Here is the adapter code:
function submitBroadcastNotification( notificationText) {
var notification = {};
notification.message = {};
notification.message.alert = notificationText;
//notification.target = {};
//notification.target.tagNames = ['test'];
WL.Logger.debug("broadcast: " + notification.message.alert );
var delayTimeOut = **WL.Server.sendMessage**("PushNotificationsApp", notification);
WL.Logger.debug("Return value from WL.Server.sendMessage :"+ delayTimeOut);
return {
result : "Notification sent to all users"
};
}
Here is the PushBackendEmulator code:
public static void main(String [] args){
String serverUrl =
"http://208.124.245.78:9080/worklight";
String notificationText = "Hellofrombroadcastingnotifications";
String userId = "admin";
notificationText = notificationText.replace(" ", "%20");
Logger.debug("sending broadcast notification: " + notificationText);
URL url = new URL(serverUrl
+ "/invoke?
adapter=PushAdapter&procedure=submitBroadcastNotification¶meters=['" + userId + "','" + notificationText + "']");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(10000);
connection.setDoOutput(true);
Logger.debug("Connected to server");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = "";
String inputLine;
while ((inputLine = in.readLine()) != null)
response+= inputLine;
Logger.debug("response is:"+ response);
in.close();
Logger.debug("Server response :: " + response);
connection.disconnect();
Looking at your application from the PMR, it seems to me like you have mixed both event source-based notifications and broadcast notifications.
If you want to use Broadcast notifications, this means you cannot try imposing sending the notification to any specific userId, etc as it is not needed nor based on userIds.
By default, all devices are auto-subscribed to a tag called "push.ALL".
You can read more about broadcast notifications API methods in the IBM Worklight Knowledge Center.
This is a modified version of your application, tested in iOS and Android: https://www.dropbox.com/s/l2yk2pbvykrzfoh/broadcastNotificationsTest.zip?dl=0
Basically, I stripped away from it anything not related to broadcast notifications:
I removed the push securitytest from application-descriptor.xml
I removed any function from the adapter XML and JS files and main.js file that is related to event source-based notifications.
The end result is that after the app is loaded, you are right inside the application (no login).
I then right-clicked the adapter folder in Studio > invoke procedure, and selected the submitBroadcastNotification option to send the notification ("aaa").
In the device, a notification was received. Tapping it (if the app is closed) launches the application, which then triggers the WL.Client.Push.onMessage API in common\js\main.js to display alerts containing the payload and props of the received notification.
This was tested in both iOS and Android.
As the application was loading, I could see in LogCat and Xcode console the token registration.
To test this in iOS, you will need to update application-descriptor.xml with your own pushSender password and add your own apns-certificatae-sandbox.p12 file.
To test in Android, make sure you are have generated a browser key in the GCM console and are using it in application-descriptor.xml
For both, make sure that all requires ports and addresses and accessible in your network
I am developing a vehicle tracking system which uses GPS/GPRS/GSM. The tracking device I am currently using is GV100, a GPS/GPRS/GSM tracker from Quectel ([www.quectel.com][1].)
I am not able to establish connection between the device and the backend server. My question particularly is:
How do I send commands (AT Commands) to the device from the server?
How do I accept the response (reports and acknowledgement messages) from the device to save it in the database?
I sent command to the device with the MGV100 Manage Tool (Software provided by Quectel) via serial port. And I got acknowledgement SMS message on GSM enabled mobile telephone. Now, I want to send message from the server and accept reply on the server (not by SMS). I don’t know how to send command and receive the reply. I have no previous experience in developing such systems.
It would be great if I can get a sample code and setup procedures if it requires.
Where can I get a relevant tutorial for the case I mentioned?
Thanks jhonkola
To understand how server receives and send data to the device, I decided to first implement the communication between the client (currently my PC) and server. Though my ultimate goal is communicating with the device, currently I am trying to establish connection from my PC to the server. If I succeed in this, I will strive to communicate to server from the device which needs IP address and port number of server to send and receive data.
This is my assumption how to do it:
I can open a port on the server from .cs code so as to communicate
using TCP/UDP.
Client then can send and receive data via this
port.
I can save the data sent from the client on server's file
system and review it any time. (Am not storing the data in relational database because I don't want to bother about database issues now.)
This is how I tried to implement:
Server a C# Web Application:
When a button is clicked it opens a port and listens to client
protected void btnConnect_Click(object sender, EventArgs e)
{
try
{
continueListening = true;
while (continueListening)
{
int port=Int32.Parse(txtPort.Text);
lblOutput.Text = "Port is now " + port +". Waiting for connection";
TcpListener myList = new TcpListener(IPAddress.Parse(txtIpAddress.Text), port);
myList.Start();
Socket s = myList.AcceptSocket();
lblOutput.Text="Connection accepted from " + s.RemoteEndPoint;
byte[] b = new byte[100];
int k = s.Receive(b);
lblOutput.Text = ("Recieved...");
String obtainedText = "";
for (int i = 0; i < k; i++)
{
obtainedText = obtainedText + " " + (Convert.ToChar(b[i]));
}
writeToTextFile("C:/Users/MekAtIbex/Desktop/TESTED/RECIEVED.txt", obtainedText);
lblOutput.Text = obtainedText;
ASCIIEncoding asen = new ASCIIEncoding();
lblOutput.Text = lblOutput.Text +" "+ ("The string was recieved by the server.");
lblOutput.Text = lblOutput.Text +" "+ ("\r\nSent Acknowledgement");
}
Client: C# Windows application
private void btnSend_Click(object sender, EventArgs e)
{
try
{
TcpClient tcpClient = new TcpClient();
int port=Int32.Parse(txtPort.Text.Trim());
tcpClient.Connect(txtIpAddress.Text, port);
lblStatus.Text = ("Connected");
Stream stm = tcpClient.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] bytesToSend = asen.GetBytes(txtData.Text);
lblStatus.Text = ("Transmitting.....");
stm.Write(bytesToSend, 0, bytesToSend.Length);
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
{
txtaResponse.Text = txtaResponse.Text + "\n" + "Res... " + new DateTime() + " " + Convert.ToChar(bb[i]);
Console.Write(Convert.ToChar(bb[i]));
}
tcpClient.Close();
}
catch (Exception ex)
{
lblStatus.Text = ("Connected");
txtaRequest.Text = txtaRequest.Text + "\n" + "Err... " + new DateTime() + " " + ex.StackTrace;
}
}
My current questions are:
Is my assumption correct? If not how should I do it?
I have tried to save it using the above code but I didn't got the file.
What is the advantage and disadvantage of using UDP in comparison TCP for tracking applications?
I have browsed well, but I couldn't find a place for a good start. And, as I have no experience in such applications, I couldn't debug my application.
My current questions are:
Is my assumption correct? If not how should I do it?
Yes, your basic assumptions are correct. The server would open a listening port and then the client could connect to this port and drop off data as needed. You can have the server log this to a file for later review too.
I have tried to save it using the above code but I didn't got the
file.
Is the file already created? The method you have will fail if the file is not existent on the system.
What is the advantage and disadvantage of using UDP in comparison TCP
for tracking applications?
UPD is less expensive in terms of network setup. It is the "fast and dirty" method of communication. The downside is that you may not get every message properly delivered. In some applications, this just doesn't matter and the benefits are worth this cost.
Now a few things I'd change:
Change IPAddress.Parse(txtIpAddress.Text) to IPAddress.Any
This will allow your listener the broadest ability to catch incoming messages and will most likely not effect other systems (since this is essentially your first networking program).
You'll also want to make your listener spawn a thread to handle the file writing and then go back to listening. This is a very standard practice and allows for servers to handle multiple connections.
It is difficult to comprehensively answer this, as a good answer would require detailed knowledge about the product. I suggest that you contact the manufacturer / reseller for support.
A few general points:
Sending commands over network to the device requires that you are able to connect to the device from internet. This is not always easy over GSM network, as the operators may block all incoming traffic. The manufacturer may have provided solutions for this.
If you can connect to the device, the protocol that is used to give commands (assuming that such protocol is built-in) will also contain a mechanism to receive any responses.
I am trying to figure out how to send an email from a Flash Mobile (smartphones: blackberries, iphones, androids) app using mxml and Flash using Flash Builder 4.6. My boss told me to find out if it is possible. So far, I have been doing a lot of searching around on the internet for an answer.
I found this website: http://www.bytearray.org/?p=27, that has some classes for sending email in flash, but #1, I don't know if they work in Mobile apps, and #2, I can't find any instructions or tutorials on how to use the classes to send a simple email.
I downloaded the package from the site and imported into my project, where I am trying to send the code. But without sample code on how to simply send an email, I am not entirely sure what all do, and nor am I sure how to determine things like what port number to construct the SMTPMailer object (the SMTPMailer object is included in that package, and it takes a host string and a port number integer in it's constructor), right now I am trying 80 or 8080 for the port number, and I've tried localhost and one of our server computers, 198.162.1.109 for the host.
Anyway, I keep getting this error: Error #2044: Unhandled IOErrorEvent:. text=Error #2031: Socket Error.
Here is some of my sample code:
[Bindable]
private var mailer : SMTPMailer;
private function init() : void {
tbPass.displayAsPassword = true;
}
protected function btnClick_email(toAddress : String, fromAddress : String, pass : String) : void {
mailer = new SMTPMailer("198.168.1.109", 8080);
mailer.addEventListener(SMTPEvent.MAIL_SENT, onMailSent);
mailer.addEventListener(SMTPEvent.MAIL_ERROR, onMailError);
mailer.addEventListener(SMTPEvent.CONNECTED, onConnected);
mailer.addEventListener(SMTPEvent.DISCONNECTED, onDisconnected);
mailer.connect("hotmail.com", 8080);
mailer.authenticate(toAddress, pass);
mailer.sendHTMLMail(fromAddress, toAddress, "Subect", "Message");
}
private function onMailSent() : void {
lblEmailResult.text = "Sent Mail";
}
private function onMailError() : void {
lblEmailResult.text = "Error";
}
private function onConnected() : void {
lblEmailResult.text = "Connected";
}
private function onDisconnected() : void {
lblEmailResult.text = "Disconnected";
}
I would suggest using a back-end service to send emails, it is same as connecting to a SMTP mail server but it is more flexible.
That being said, it should work, the error you are getting is related to your host IP, are you sure you have SMTP server running on "198.168.1.109:8080"?
First check if you can send mails from it before trying to do it trough Flex, if that is OK, then you should double check socket policy files:
http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html
Hope that helps
Can't you just use navigateToURL() for this?
Ie:
var request:URLRequest("mailto:someone#somewhere.com");
navigateToURL(request);
That's all - 2 lines :)
I've accomplished this in a commercial app I worked on. We used a native extension found in distriqt's set of tools. Google them. The full suite of tools is cheap, though if you have any issues, do not expect a quick reply. Their message tool is what you are looking for, and it is easy to use.
I worked on a sample application integrating OpenID into ASP.NET Web Forms. It works fine when hosted locally on my machine. However, when I uploaded the application to a live server, it started giving "Login Failed".
You can try a sample here: http://samples.bhaidar.net/openidsso
Any ideas?
Here is the source code that fails to process the OpenID response:
private void HandleOpenIdProviderResponse()
{
// Define a new instance of OpenIdRelyingParty class
using (var openid = new OpenIdRelyingParty())
{
// Get authentication response from OpenId Provider Create IAuthenticationResponse instance to be used
// to retreive the response from OP
var response = openid.GetResponse();
// No authentication request was sent
if (response == null) return;
switch (response.Status)
{
// If user was authenticated
case AuthenticationStatus.Authenticated:
// This is where you would look for any OpenID extension responses included
// in the authentication assertion.
var fetchResponse = response.GetExtension<FetchResponse>();
// Store the "Queried Fields"
Session["FetchResponse"] = fetchResponse;
// Use FormsAuthentication to tell ASP.NET that the user is now logged in,
// with the OpenID Claimed Identifier as their username.
FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, false);
break;
// User has cancelled the OpenID Dance
case AuthenticationStatus.Canceled:
this.loginCanceledLabel.Visible = true;
break;
// Authentication failed
case AuthenticationStatus.Failed:
this.loginFailedLabel.Visible = true;
break;
}
}
As Andrew suggested, check the exception. In my case, my production server's time & date were off and it wouldn't authenticate because the ticket expired.
Turn on logging on your live server and inspect them for additional diagnostics. It's most likely a firewall or permissions problem on your server that prevents outbound HTTP requests.
You may also find it useful to look at the IAuthenticationResponse.Exception property when an authentication fails for clues.