servchan/tools/optisign/optisign.js
jmcqueen c2e98d105e Initial commit: ServChan Webex bot for ServiceChannel work orders.
ServiceChannel webhook processor, proposal approval cards, attachment auto-post,
CollabSupport commands, and Docker deployment configuration.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 15:12:08 -04:00

111 lines
No EOL
4.7 KiB
JavaScript

//const { GraphQLClient, gql } = require('graphql-request');
import { GraphQLClient, gql } from 'graphql-request';
async function getStoreDevicesStatus(storeNumber, apiKey) {
const endpoint = 'https://graphql-gateway.optisigns.com/graphql';
const client = new GraphQLClient(endpoint, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const paddedStore = storeNumber.toString().padStart(6, '0');
const query = gql`
query GetDevices($first: Int, $after: String) {
devices(query: {}, first: $first, after: $after) {
page {
edges {
node {
_id
deviceName
UUID
pairingCode
currentType
currentAssetId
currentPlaylistId
localAppVersion
lastHeartBeat # Confirmed field!
# status # still null in sample, but can keep if it populates sometimes
# updatedAt # if you see it later
}
}
pageInfo { hasNextPage endCursor }
}
}
}
`;
let allDevices = [];
let after = null;
const pageSize = 50;
try {
do {
const data = await client.request(query, { first: pageSize, after });
allDevices = allDevices.concat(data.devices.page.edges.map(e => e.node));
after = data.devices.page.pageInfo.hasNextPage ? data.devices.page.pageInfo.endCursor : null;
} while (after);
const storeDevices = allDevices.filter(d => d.deviceName?.includes(paddedStore));
if (storeDevices.length === 0) {
return [];
}
return storeDevices;
/* storeDevices.forEach(device => {
let statusLine = '• **Playback Status:** Idle / Not playing';
let details = '';
if (device.currentPlaylistId || device.currentAssetId) {
const isPlaylist = device.currentType === 'PLAYLIST' || !!device.currentPlaylistId;
statusLine = `• **Playback Status:** Active - Playing content (${isPlaylist ? 'Playlist' : 'Asset/Single'})`;
details = `\n - Assigned ID: ${device.currentPlaylistId || device.currentAssetId || 'N/A'}\n - Type: ${device.currentType || 'unknown'}\n - App Version: ${device.localAppVersion || 'N/A'}`;
}
// Heartbeat / Connectivity Status
let heartbeatInfo = '';
if (device.lastHeartBeat) {
const hbDate = new Date(device.lastHeartBeat);
const now = new Date(); // Current time in UTC, then we'll adjust display
const minutesAgo = Math.round((now - hbDate) / 60000);
const hbLocal = hbDate.toLocaleString('en-US', { timeZone: 'America/New_York' });
heartbeatInfo = `\n - Last Heartbeat: ${hbLocal} (${minutesAgo} min ago)`;
if (minutesAgo <= 10) {
heartbeatInfo += ' 🟢 **Online & checking in** (likely synced)';
} else if (minutesAgo <= 30) {
heartbeatInfo += ' 🟡 **Possibly delayed**';
} else {
heartbeatInfo += ' 🔴 **Offline / not checking in**';
}
} else {
heartbeatInfo = '\n - No heartbeat data available';
}
md += `**${device.deviceName}** (${device.UUID.substring(0, 8)}...)\n`;
md += `${statusLine}\n`;
md += `${details}${heartbeatInfo}\n\n`;
});
md += `**Last checked:** ${new Date().toLocaleString('en-US', { timeZone: 'America/New_York' })} EST\n`;
md += `(via OptiSigns API)`;
console.log(md);
return md;
*/
} catch (error) {
const errMd = `**Error:** ${error.message}`;
console.error(errMd);
return errMd;
}
}
// Example usage
const apiKey = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJnaEF3SEhKdTdkS3RmcEdkTSIsImNpZCI6Ilk2cXlaZXAzSE1NeHBuYXRMIiwiYWlkIjoidHh1NGhUcnZEMkdaM25tOU0iLCJpYXQiOjE3NDc0MTAxNjgsImV4cCI6MTc0NzQxMzc2OCwiaXNzIjoidHh1NGhUcnZEMkdaM25tOU0ifQ.TZRzzV6-QejdW4H3vppeypzExv4ppHdIKHSHpZXbKmpDhktlWrOQLQf4sNeX-UPa0bKKQcp9b8qHGpeu163bhmQAnnkWROqMD2z8tZ2kKgW34iXH5B_Ur1TbylvUS_ZsfFDQiUnT1Lf9waMAhZJeYKP4j70ak7BclMFf7XMGNGy75vSknzi1x7nvB1AOS5kEcPIV_oZNXlBVLLnEM1t3Edk6K-jXDmR_XHqN0lI3t0NX0yr2VTgt2KSqDRPaGcNBmuXHUgeB8xsEW4Dlk8rIin7qW4WkrvycnjyL2ZpT9EFZWYjaQNyJoTmJjxeywl9JrzrO1sIoYJ0QdHAOmgsnIDiYnw_eR73Mi0l3QUC9fZfgD91gidwKMWt3LIm4KCkynRNPOlBz7UGTp_wb4qCSFCNiYB6fGhWT1u7rcoR1g7sCHwCX6pkSMhKs1ZSOprTZSUFeFloqE3ufCNACQMa5I8QYi4Lz7KdEOn9yK2UM13Te1Shs3fD2HS23pyiLjznBMQg9z5TWTzbPWteR7FyKIRZjtdF1Foe5BJp-EmN_FR74Ndz1lo-0b10stszQE18ob9HSWsmWu_Tqg_KG4wBxOzKM-V8Eksx4eFyHeh8lzGXESzH2pGYfs7M3Y5Dvy1a3Hy9Xh7O0n82EW9MUHTXiny3yycD9vuUyG4FNQ7K2NuY'; // Replace with your actual key
const storeNumber = "002248";
const deviceName = 'US000629VW02'; // Replace with your device name (e.g., incorporating the 6-digit store number)
getStoreDevicesStatus(storeNumber, apiKey);