Debugging Websocket Connect

I'm trying to build a driver that connects to the Ambient Weather websocket API

My driver code contains:

    interfaces.webSocket.connect("https://api.ambientweather.net/?api=1&applicationKey=" + applicationKey)

But here is what I get back on the webSocketStatus callback:

 failure: unexpected end of stream on Connection{api.ambientweather.net:443, proxy=DIRECT hostAddress=api.ambientweather.net/107.170.198.71:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=http/1.1}

I've verified their API does actually work with the node app they publish: ambient-weather-api/realtime.js at master · owise1/ambient-weather-api · GitHub

Debugging that shows what I'd expect as well as far as request/response data. Any tips on how to debug this?

Here is the full driver: ambient_websocket.groovy · GitHub

And the debug log from the nodejs/socket.io client that works: socket.io log · GitHub

https??
Shouldn't it be ws:// ??

Sorry should have mentioned I tried that as well with the same error:

failure: unexpected end of stream on Connection{api.ambientweather.net:80, proxy=DIRECT hostAddress=api.ambientweather.net/107.170.198.71:80 cipherSuite=none protocol=http/1.1}

Their demo nodejs app uses https. I'm wondering if the HTTPS request gets upgraded to a WS request and maybe hubitat doesn't support that? I guess I might have to write a browser based JS version so I can really watch all the network traffic :frowning:

Don't bother. You cannot make it work. It uses socket.io which is a proprietary websocket implementation that is not compatible with Hubitat's. The key takeaway is:

"The easiest way to use the API is to use a Socket.io helper library."

Websockets

The realtime API uses Websockets and is based on Socket.io (https://socket.io/). The easiest way to use the API is to use a Socket.io helper library. They are available in most languages.

Socket.io Endpoint: https://rt.ambientweather.net/?api=1&applicationKey=....

Note the query parameters api=1 to identify the api version and applicationKey=.... to identify your application

Don't waste your time any further. If you want this to work, you'll have to create a nodeJS app with a socket.io client to connect to their websocket, and a standard websocket server for the hub to connect to.

2 Likes

Thank you for the help and that is quite annoying that they're using a non-standard websocket system. Also I don't feel so bad I couldn't get it working :stuck_out_tongue:

1 Like

@chuck.schwer is aware of my desire to have this adde at some point in the future..

In the meantime, I have the nodeJS code you can adapt if you want to make this work.

1 Like

While @srwhite was 58%20AM last summer, I decided it would be very cool to insert a proxy in Hubitat's Event Socket and then tap into the combined stream from multiple hubs to do logging. I prototyped it and it did what I expected.... Fast forward to Steve's return and he says he's been thinking of.. yep, a proxy for Hubitat's Event Stream. I tell him just how ironic that is to me, and in my memory it's maybe 45 mins later he's telling me he got it working.

Eventually that became what is HubConnect (NodeJS) Server in v2.0. When I got his for testing, it didn't work at all... because MY version used "websocket.js" library and his uses "ws.js"

Embarrassing to read it, see it, miss it. Same as above.. I saw "socket.io" -- didn't SEE it :slight_smile:

If you wouldn't mind sharing I'd be interested. My weather station data isn't critical so I don't mind having it depend on having my rPi being running as well.

It happens to all of us... More frequently as we age. :wink:

Sure.. I had to solve this issue very recently. You'll have to adapt it to work for you, but feel free to use this code however you wish. It has basic connection recovery but might need a little more polish.

index.js
/**

  • HubConnect Automatic Proxy
  • Copyright 2019 Steve White, Retail Media Concepts LLC.
  • HubConnect for Hubitat is a software package created and licensed by Retail Media Concepts LLC.
  • HubConnect, along with associated elements, including but not limited to online and/or electronic documentation are
  • protected by international laws and treaties governing intellectual property rights.
  • This software has been licensed to you. All rights are reserved. You may use and/or modify the software.
  • You may not sublicense or distribute this software or any modifications to third parties in any way.
  • By downloading, installing, and/or executing this software you hereby agree to the terms and conditions set forth in the HubConnect license agreement.
  • http://irisusers.com/hubitat/hubconnect/HubConnect_License_Agreement.html
  • Hubitat is the trademark and intellectual property of Hubitat, Inc. Retail Media Concepts LLC has no formal or informal affiliations or relationships with Hubitat.
  • Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  • on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License Agreement
  • for the specific language governing permissions and limitations under the License.

*/
const appVersion = {platform: "NodeJS", major: 1, minor: 0, build: 0}
var WebSocket = require('ws');
const config = require('./config.json');

console.log(`HubConnect-Automatic Websocket Proxy Server v${appVersion.major}.${appVersion.minor}.${appVersion.build}\nCopyright 2019-2020 Retail Media Concepts LLC\nAll Rights Reserved\n\n`);
console.log("Initializing connections...\n\n")


// HubConnect Websocket Server
socketServer = new WebSocket.Server({port: config.port, perMessageDeflate: false});
socketServer.connectionCount = 0;
socketServer.on('connection', function(socket,request)
{
  socketServer.connectionCount++;

  console.log(
    `Hubitat: ${socket._socket.remoteAddress}; ${socketServer.connectionCount} connected.`
  );

  socket.on('close', function(code, message)
  {
      socketServer.connectionCount--;
      console.log(
          `Hubitat: Hub disconnected; (${socketServer.connectionCount} connected)`
      );
  });
});


// Automatic Cloud Listener
var io = require('socket.io-client')
function automatic()
{
  console.log (`Automatic: Connecting to the Automatic cloud websocket...`);
  var autoSocket = io(`https://stream.automatic.com?token=${config.client_id}:${config.client_secret}`)


  // Handle error messages
  autoSocket.on('error', function(errorMessage)
  {
    console.log('Automatic: Error', errorMessage);
  });

  // Notify console of the connection success
  autoSocket.on('connect', function()
  {
    console.log('Automatic: Connected to the Automatic cloud!');
  });

  // Handle disconnect messages
  autoSocket.on('disconnect', function(errorMessage)
  {
    console.log('Automatic: Lost connection to Automatic cloud!  Retrying in 30 seconds...', errorMessage);
    setTimeout(automatic, 30000);
  });
}
automatic();

function sendAutomaticEvent(eventType, eventData)
{
  socketServer.clients.forEach(function each(client)
  {
    if (client.readyState === WebSocket.OPEN)
    {
      client.send(JSON.stringify({source: eventType, data: eventData}));
    }
  });
}

config.json
{
"client_id": "e4060ac1f42c658346ed",
"client_secret": "c4973cf67de9887c0ff5367bb2c7413f90d5b97b",
"port": 22200
}

package.json
{
"name": "automatic",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": ,
"author": "",
"license": "ISC",
"dependencies": {
"socket.io-client": "^2.3.0"
}
}

Hope this can help.

It looks like the formatting blew up.. Apologies for that. I cannot seem to fix it either.

maybe:

Index.js

/**
HubConnect Automatic Proxy
Copyright 2019 Steve White, Retail Media Concepts LLC.
HubConnect for Hubitat is a software package created and licensed by Retail Media Concepts LLC.
HubConnect, along with associated elements, including but not limited to online and/or electronic documentation are
protected by international laws and treaties governing intellectual property rights.
This software has been licensed to you. All rights are reserved. You may use and/or modify the software.
You may not sublicense or distribute this software or any modifications to third parties in any way.
By downloading, installing, and/or executing this software you hereby agree to the terms and conditions set forth in the HubConnect license agreement.
http://irisusers.com/hubitat/hubconnect/HubConnect_License_Agreement.html
Hubitat is the trademark and intellectual property of Hubitat, Inc. Retail Media Concepts LLC has no formal or informal affiliations or relationships with Hubitat.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License Agreement
for the specific language governing permissions and limitations under the License.
*/
const appVersion = {platform: "NodeJS", major: 1, minor: 0, build: 0}
var WebSocket = require('ws');
const config = require('./config.json');

console.log(`HubConnect-Automatic Websocket Proxy Server v${appVersion.major}.${appVersion.minor}.${appVersion.build}\nCopyright 2019-2020 Retail Media Concepts LLC\nAll Rights Reserved\n\n`);
console.log("Initializing connections...\n\n")


// HubConnect Websocket Server
socketServer = new WebSocket.Server({port: config.port, perMessageDeflate: false});
socketServer.connectionCount = 0;
socketServer.on('connection', function(socket,request)
{
  socketServer.connectionCount++;

  console.log(
    `Hubitat: ${socket._socket.remoteAddress}; ${socketServer.connectionCount} connected.`
  );

  socket.on('close', function(code, message)
  {
      socketServer.connectionCount--;
      console.log(
          `Hubitat: Hub disconnected; (${socketServer.connectionCount} connected)`
      );
  });
});


// Automatic Cloud Listener
var io = require('socket.io-client')
function automatic()
{
  console.log (`Automatic: Connecting to the Automatic cloud websocket...`);
  var autoSocket = io(`https://stream.automatic.com?token=${config.client_id}:${config.client_secret}`)


  // Handle error messages
  autoSocket.on('error', function(errorMessage)
  {
    console.log('Automatic: Error', errorMessage);
  });

  // Notify console of the connection success
  autoSocket.on('connect', function()
  {
    console.log('Automatic: Connected to the Automatic cloud!');
  });

  // Handle disconnect messages
  autoSocket.on('disconnect', function(errorMessage)
  {
    console.log('Automatic: Lost connection to Automatic cloud!  Retrying in 30 seconds...', errorMessage);
    setTimeout(automatic, 30000);
  });
}
automatic();

function sendAutomaticEvent(eventType, eventData)
{
  socketServer.clients.forEach(function each(client)
  {
    if (client.readyState === WebSocket.OPEN)
    {
      client.send(JSON.stringify({source: eventType, data: eventData}));
    }
  });
}

config.json

{
"client_id": "e4060ac1f42c658346ed",
"client_secret": "c4973cf67de9887c0ff5367bb2c7413f90d5b97b",
"port": 22200
}

package.json

{
"name": "automatic",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"socket.io-client": "^2.3.0"
}
}

Not sure what the secret sauce for that was, but thanks!

I've reached the end of my development time until later this evening. The honey-do list is calling. :slight_smile:

1 Like

50%20AM

Select the Code, click the </> then immediately click "

That's it. :slight_smile: Takes TWO of the options.

1 Like

I know this thread says don't waste your time getting Socket.io working, but do you think there is any chance Socket.io support will be added at any point? Would be a super useful addition for a couple of integrations I have in mind....
Thanks!