Can someone who has gotten a CMX https receiver to work tell me their setup?

joincidence
Getting noticed

Can someone who has gotten a CMX https receiver to work tell me their setup?

I've been trying to get this to work with Meraki Location and Scanning

 

https://developer.cisco.com/meraki/scanning-api/introduction/#scanning-api

 

so it can send me data to work with. I've been using this

 

https://github.com/dexterlabora/cmxreceiver

 

It works as http, but Meraki requires https. I finally got it to work with an ssl proxy(You get validator string when you hit the URL), but Meraki still gives an error 400 when I try to verify. All the resources in that section are outdated and I can't get any of the solutions to work. Meraki support says they can't help me and to post here. I don't need a guide or anything, just someone to point me in the right direction to get this working. 

 

 

7 Replies 7
alemabrahao
Kind of a big deal
Kind of a big deal

One thing you can try is to make sure that your receiver is configured correctly to receive and process the data sent by the Scanning API. You can use the Meraki Sandbox to test your receiver before deploying it in production. 

 

Another thing you can check is the application and service logs on your receiver to see if there are any errors or warnings. You can also refer to your endpoint application/service vendor for documentation and troubleshooting assistance.

 

Scanning API for Location Analytics Solutions - Cisco Meraki Documentation

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
joincidence
Getting noticed

The receiver is configured correctly according to this:

 

https://developer.cisco.com/meraki/scanning-api/overview/#validator

 

I receive the validator string that matches the one in the Meraki portal when I navigate to the URL. 

 

There are no errors in the log for the cmx receiver. 

 

I don't know what the below text means, though:

 

"You can also refer to your endpoint application/service vendor for documentation and troubleshooting assistance."

 

There is no vendor to talk to or get support from. It's just Meraki(who won't help me with this), me, and this open source cmx receiver that was included in their resources for setting it up. 

alemabrahao
Kind of a big deal
Kind of a big deal

I got it, but why won't they help? Don't you have their support?

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
joincidence
Getting noticed

I have support, yeah. I've had many cases with them, and I have a multitude of API-related stuff working. For some reason, they won't help with this specific thing. 

alemabrahao
Kind of a big deal
Kind of a big deal

In any case, the only way is even with HTTPS, since Meraki no longer supports HTTP for a long time.

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
joincidence
Getting noticed

I'm painfully aware of that fact, lol. In all of my efforts trying to get this to work, I've since learned how to set up apache servers, get certificates working, and a bunch of other interesting stuff. I just can't get this cmx receiver to work with Meraki. 

 

What's weird is there was some bug where Meraki was actually talking to my http server and sending me JSON dat despite it being http. It was basically working, but then it stopped working days later for some reason. 

PhilipDAth
Kind of a big deal
Kind of a big deal

I've only ever done it in Amazon AWS using a Lambda script (as that provides a public SSL certificate, and you pay for runtime, which is very cheap).

 

This is some node.js code that I wrote.  I hope I have removed enough to prevent getting myself in trouble while leaving it as helpful.

 

const debug=true;
const secret = process.env.secret;
const validator = process.env.validator;
const sql = "INSERT INTO dim_meraki_wifi (apiVer, type, clientMac, seenTime, ssid, rssi, lat, lng, unc, x, y);

// Create a pool of database connections
const { Client } = require('pg')

exports.handler = (event, context, callback) => {
  //context.callbackWaitsForEmptyEventLoop = false;

  // Return the validator
  if(event.httpMethod=='GET') {
    if(debug) console.log('Processing GET request');
    callback(null, {
      statusCode: '200',
      body: validator,
      headers: {'Content-Type': 'text/plain'}
    });
    return;
  }

  // We only process POST methods after processing the GET
  if(event.httpMethod !='POST') {
    if(debug) console.log('Processing POST request');
    callback(null, {
      statusCode: '403',
      body: "request not recognized",
      headers: {'Content-Type': 'text/plain'}
    });
    return;
  }

  const apiData = JSON.parse(event.body);
  if(debug) {
    console.log('apiData:');
    console.log(apiData);
    console.log(apiData.data.observations);
  }

  // Check the right secret has been supplied
  if(apiData.secret != secret) {
    console.log("secret invalid: "+ apiData.secret);
    callback(null, {
      statusCode: '403',
      body: "INVALID SECRET",
      headers: {'Content-Type': 'text/plain'}
    });
    return;
  }

  // Check which version of API data we have been given
  if(apiData.version=='2.0') {
    let key;
    const o = apiData.data.observations;

    if(apiData.type == "DevicesSeen" || apiData.type == "BluetoothDevicesSeen") {
      if(debug) console.log('Processing V2 request: '+ apiData.type);

      for (key in o) {
        if (o.hasOwnProperty(key)) {
          if (!o[key].location) break;
          if (o[key].seenEpoch == null || o[key].seenEpoch == 0) break;  //  # This probe is useless, so ignore it
        }

      	// Put item into PostgreSQL
      	const values=[apiData.version,apiData.type,o[key].clientMac,o[key].seenTime,o[key].ssid,o[key].rssi,o[key].location.lat,o[key].location.lng,o[key].location.unc,o[key].location.x[0],o[key].location.y[0]];
        if(debug) console.log('Processing SQL: '+sql+' '+values);

        const client = new Client();
        client.connect();
        client.query(sql,values,(err, res) => {
          if (err) console.log('client.query():error: '+err);
          else {
            if(debug) console.log('client.query():success: '+JSON.stringify(res));
          }
          client.end();
        });
      }
    }
  } else if(apiData.version=='3.0') {
    let x;
    const o = apiData.data.observations;

    // Process V3 WiFi observations
    if(apiData.type == "WiFi") {
      if(debug) console.log('Processing V3 request: '+ apiData.type);

      // Lop through all the observations
      for (x in o) {
        // Skip observations with no locations
        if(o[x].locations.length==0) continue;
        
        // Loop through all the locations in the observation
        let y;
        for(y in o[x].locations) {
          const location=o[x].locations[y];

        	// Put item into PostgreSQL
        	const values=[apiData.version,apiData.type,o[x].clientMac,location.time,o[x].ssid,o[x].latestRecord['nearestApRssi'],location.lat,location.lng,location.variance,location.x,location.y];
          if(debug) console.log('Processing SQL: '+sql+' '+values);

          const client = new Client();
          client.connect();
          client.query(sql,values,(err, res) => {
            if (err) console.log('client.query():error: '+err);
            else {
              if(debug) console.log('client.query():success: '+JSON.stringify(res));
            }
            client.end();
          });
        }
      }
    }
  } else {
    console.log("Receiver is written for version 2.0 or 3.0 and will not accept other versions. The POST data was sent with version: "+ apiData.version);
    callback(null, {
      statusCode: '403',
      body: "Invalid location API version",
      headers: {'Content-Type': 'text/plain'}
      });
    return;
  }

  // Respond to client with success
  callback(null, {
    statusCode: '200',
    body: "Location API data received",
    headers: {'Content-Type': 'text/plain'}
  });

};

 

Get notified when there are additional replies to this discussion.