Location and ID data in webhook

I have 2 borons working fine, reporting in data to the cloud portal and I have a web hook sending that data along. There are 2 things that are stumping me, if someone had an idea how to solve.

1 - the location data that is shown in the portal, is there a way to pass this along in the json of the web hook? I do not need anything near exact the level of accuracy is way more than I need for my use case. otherwise the code to do location and all that just seems like overkill…but I have tried both and had no luck.

2 - is there a way to add a variable that is the device name/id? I cannot seem to figure that one out either, so I know which device is reporting what via the web hook.

Thanks!

There is no webhook template variable for the location. If the remote service can query and cache the location from the location database using the Particle cloud API, that is one option. The other is to use Logic and the getDeviceLocation API to update the data sent to your server.

The Device ID is available using the template variable {{{PARTICLE_DEVICE_ID}}}.

version 2 :laughing: Thanks now I get it!

Here in the function I made, in case this helps anyone else.

import Particle from 'particle:core';

export default async function addLocation({ event, secrets }) {
  if (typeof event.eventData !== "string") {
    return;
  }

  let data;
  try {
    data = JSON.parse(event.eventData);
  } catch (err) {
    return;
  }

  let location = { latitude: null, longitude: null };
  let deviceName = null;
  
  if (!event.productId || event.productId === 0) {
    console.log("Device is not in a product (productId is 0 or missing)");
    console.log("Device must be added to a product in Particle Console for getDeviceLocation to work");
    console.log("Event properties:", JSON.stringify({
      deviceId: event.deviceId,
      productId: event.productId,
      eventName: event.eventName
    }));
  } else {
    try {
      console.log(`Attempting to get location for device ${event.deviceId}, product ${event.productId}`);
      
      let deviceLocation = null;
      
      // Try format 1: getDeviceLocation(productId, deviceId)
      try {
        console.log("Trying: getDeviceLocation(productId, deviceId)");
        deviceLocation = await Particle.getDeviceLocation(event.productId, event.deviceId);
        console.log("Result (productId first):", JSON.stringify(deviceLocation));
      } catch (err) {
        console.log("Failed with productId first:", err.message);
      }
      
      // Try format 2: getDeviceLocation(deviceId, { productId })
      if (!deviceLocation || (deviceLocation.status && deviceLocation.status >= 400)) {
        try {
          console.log("Trying: getDeviceLocation(deviceId, { productId })");
          deviceLocation = await Particle.getDeviceLocation(event.deviceId, {
            productId: event.productId
          });
          console.log("Result (deviceId first):", JSON.stringify(deviceLocation));
        } catch (err) {
          console.log("Failed with deviceId first:", err.message);
        }
      }
      
      console.log("getDeviceLocation raw response:", JSON.stringify(deviceLocation));
      
      // Check if it's an error response
      if (deviceLocation && deviceLocation.status && deviceLocation.status >= 400) {
        console.error(`getDeviceLocation error: ${deviceLocation.status} - ${deviceLocation.body?.error || 'Unknown error'}`);
        if (deviceLocation.status === 404) {
          console.error("404 error");
        }
      } else if (deviceLocation && deviceLocation.status === 200 && deviceLocation.body?.location) {
        // Successful response - location is in body.location.geometry.coordinates
        const loc = deviceLocation.body.location;
        
        // Extract device name
        if (loc.device_name) {
          deviceName = loc.device_name;
          console.log(`✓ Extracted device name: ${deviceName}`);
        }
        
        if (loc.geometry?.coordinates) {
          // GeoJSON format: coordinates are [longitude, latitude]
          const [lon, lat] = loc.geometry.coordinates;
          location = { latitude: lat, longitude: lon };
          console.log(`Extracted location from body.location.geometry.coordinates: ${location.latitude}, ${location.longitude}`);
        } else if (loc.latitude !== undefined || loc.longitude !== undefined) {
          location = {
            latitude: loc.latitude ?? null,
            longitude: loc.longitude ?? null
          };
          console.log(`Extracted location from body.location.latitude/longitude: ${location.latitude}, ${location.longitude}`);
        } else if (loc.lat !== undefined || loc.lon !== undefined) {
          location = {
            latitude: loc.lat ?? null,
            longitude: loc.lon ?? null
          };
          console.log(`Extracted location from body.location.lat/lon: ${location.latitude}, ${location.longitude}`);
        } else {
          console.log("Location object exists but no coordinates found");
          console.log("Location structure:", JSON.stringify(loc, null, 2));
        }
      } else {
        console.log("getDeviceLocation returned unexpected format");
        console.log("Response:", JSON.stringify(deviceLocation, null, 2));
      }
    } catch (error) {
      console.error("getDeviceLocation exception:", error.message);
      console.error("Error details:", JSON.stringify(error));
    }
  }

  const enriched = {
    ...data,
    location: location,
    device_name: deviceName
  };

  console.log("Final enriched data location:", JSON.stringify(location));

  await Particle.publish(
    "weatherDataWithLocation",
    JSON.stringify(enriched),
    { productId: event.productId }
  );
}
1 Like