Skip to content

Instantly share code, notes, and snippets.

@AndrewAubury
Created March 4, 2026 12:43
Show Gist options
  • Select an option

  • Save AndrewAubury/7ea1cf8470d0a5f230ca910538b32f2a to your computer and use it in GitHub Desktop.

Select an option

Save AndrewAubury/7ea1cf8470d0a5f230ca910538b32f2a to your computer and use it in GitHub Desktop.
PureGym Attenance to InfluxDB
const GYMS = {
"dunstable": 111,
"luton": 462,
"haywards_heath": 359,
};
/**
* Authenticate and return Bearer token
*/
async function authenticate(email, pin) {
const body = new URLSearchParams({
grant_type: "password",
username: email,
password: pin,
scope: "pgcapi",
client_id: "ro.client",
});
const res = await fetch("https://auth.puregym.com/connect/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0",
},
body,
});
if (!res.ok) {
throw new Error(`Auth failed: ${res.status}`);
}
const json = await res.json();
return json.access_token;
}
async function fetchGyms(token) {
const res = await fetch(
`https://capi.puregym.com/api/v2/gyms/`,
{
headers: {
"Authorization": `Bearer ${token}`,
"User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0",
},
}
);
if (!res.ok) {
const err = res.statusText
return {"err": err};
//throw new Error(`Attendance failed (${gymId}): ${res.status}`);
}
const json = await res.json();
return json
}
/**
* Fetch attendance for one gym
*/
async function fetchAttendance(token, gymId) {
const res = await fetch(
`https://capi.puregym.com/api/v2/gymSessions/gym?gymId=${gymId}`,
{
headers: {
"Authorization": `Bearer ${token}`,
"User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0",
},
}
);
if (!res.ok) {
return 0;
//throw new Error(`Attendance failed (${gymId}): ${res.status}`);
}
const json = await res.json();
if(json.TotalPeopleInGym == null){
return 0;
}else{
return json.TotalPeopleInGym;
}
}
export default {
async scheduled(event, env, ctx) {
console.log("Scheduled run at", event.scheduledTime)
ctx.waitUntil(run())
},
async fetch(request, env, ctx) {
const result = await run({ returnDetails: true })
return new Response(JSON.stringify(result, null, 2), {
status: result.ok ? 200 : 500,
headers: {
"Content-Type": "application/json"
}
})
}
}
async function run(options = {}) {
const written = []
let influxResponse = null
const token = await authenticate(
'EMAIL_HERE',
'PIN_HERE',
);
const result = {};
await Promise.all(
Object.entries(GYMS).map(async ([name, gymId]) => {
try {
result[name] = await fetchAttendance(token, gymId);
} catch {
result[name] = null;
}
})
);
const data = result;
// Build InfluxDB line protocol
const lines = []
for (const [location, count] of Object.entries(data)) {
lines.push(`gym_occupancy,location=${location} count=${count}`)
written.push({ location, count })
}
const body = lines.join("\n")
// Write to InfluxDB
const influxRes = await fetch(
"https://influxdb.example.com/api/v2/write?org=org_here&bucket=bucket_here&precision=s",
{
method: "POST",
headers: {
"Authorization": "Token token_here",
"Content-Type": "text/plain"
},
body
}
)
const influxText = await influxRes.text()
if (!influxRes.ok) {
console.error("Influx write failed", influxRes.status, influxText)
return options.returnDetails
? {
ok: false,
written,
influx: {
status: influxRes.status,
body: influxText
},
}
: undefined
}
influxResponse = {
status: influxRes.status,
body: influxText || "OK"
}
return options.returnDetails
? {
ok: true,
written,
influx: influxResponse,
}
: undefined
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment