Skip to content

Instantly share code, notes, and snippets.

@hcgatewood
Last active October 20, 2025 00:44
Show Gist options
  • Save hcgatewood/02f18e736093e7d308dcbebd383bcc27 to your computer and use it in GitHub Desktop.
Save hcgatewood/02f18e736093e7d308dcbebd383bcc27 to your computer and use it in GitHub Desktop.
Automated apartment complex buzzer entry
// DIY version of e.g. https://lowkeybuzzer.com
const axios = require("axios");
exports.handler = async function(context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
const logWebhookUrl = context.DISCORD_WEBHOOK_LOGS || "";
const doGrantAccess = ["", "true", "1", "yes"].includes((context.DO_GRANT_ACCESS || "").toLowerCase()); // default true
const doForward = ["", "true", "1", "yes"].includes((context.DO_FORWARD_CALLS || "").toLowerCase()); // default true
const buzzerNumber = context.BUZZER_PHONE_NUMBER || "";
const forwardNumber = context.PERSONAL_PHONE_NUMBER || "";
if (buzzerNumber === "") {
console.warn("BUZZER_PHONE_NUMBER environment variable is not set");
}
if (forwardNumber === "") {
console.warn("PERSONAL_PHONE_NUMBER environment variable is not set");
}
const digitsAccept = context.DIGITS_ACCEPT || "9";
const digitsAcceptExtra = context.DIGITS_ACCEPT_EXTRA || "";
const pauseSecsBefore = Number(context.PAUSE_SECONDS_BEFORE) || 7;
const pauseSecsExtraBefore = Number(context.PAUSE_SECONDS_EXTRA_BEFORE) || 3;
const pauseSecsAfter = Number(context.PAUSE_SECONDS_AFTER) || 3;
const log = async (msg) => {
console.log(msg);
if (logWebhookUrl === "") {
return;
}
try {
await axios.post(logWebhookUrl, { content: msg });
} catch (err) {
console.error(`Error sending log to Discord: ${err}`);
}
};
// Handle buzzer call
if (event.From === buzzerNumber) {
// Grant access
if (doGrantAccess) {
await log(`Receiving call from ${event.From}. Detected as buzzer call. Granting access.`);
twiml.pause({ length: pauseSecsBefore });
twiml.play({ digits: digitsAccept });
if (digitsAcceptExtra !== "") {
twiml.pause({ length: pauseSecsExtraBefore });
twiml.play({ digits: digitsAcceptExtra });
}
} else {
await log(`Receiving call from ${event.From}. Detected as buzzer call. Denying access.`);
}
twiml.pause({ length: pauseSecsAfter });
} else {
// Forward everything else, e.g. for phone number verification
if (!doForward) {
await log(`Receiving call from ${event.From}. Detected as normal call. Won't forward since call forwarding is disabled.`);
} else if (forwardNumber === "") {
await log(`Receiving call from ${event.From}. Detected as normal call. Won't forward since forward number not configured.`);
} else {
await log(`Receiving call from ${event.From}. Detected as normal call. Forwarding to ${forwardNumber}.`);
twiml.dial(forwardNumber);
}
}
callback(null, twiml);
};
const axios = require("axios");
exports.handler = async function(context, event, callback) {
// NOTE: requires the "axios" NPM package added to the Twilio Service's dependencies
// NOTE: proactive SMS messaging requires registering as a sole proprietor
// REF: https://www.twilio.com/docs/messaging/compliance/a2p-10dlc/direct-sole-proprietor-registration-overview
// REF: https://console.twilio.com/us1/develop/sms/regulatory-compliance/a2p-10dlc-overview
const twiml = new Twilio.twiml.MessagingResponse();
const logWebhookUrl = context.DISCORD_WEBHOOK_LOGS || "";
const doForwardSMS = ["", "true", "1", "yes"].includes((context.DO_FORWARD_SMS || "").toLowerCase()); // default true
const doForwardDiscord = ["", "true", "1", "yes"].includes((context.DO_FORWARD_DISCORD || "").toLowerCase()); // default true
const forwardSMSNumber = doForwardSMS ? (context.PERSONAL_PHONE_NUMBER || "") : "";
const forwardDiscordURL = doForwardDiscord ? (context.DISCORD_WEBHOOK_SMS || "") : "";
const doForward = (forwardSMSNumber !== "") || (forwardDiscordURL !== "");
const log = async (msg) => {
console.log(msg);
if (logWebhookUrl === "") {
return;
}
try {
await axios.post(logWebhookUrl, { content: msg });
} catch (err) {
console.error(`Error sending log to Discord: ${err}`);
}
};
// Forward everything, e.g. for phone number verification
if (!doForward) {
await log(`Receiving SMS from ${event.From}. Won't forward since no forward configured.`);
}
if (forwardSMSNumber !== "") {
await log(`Receiving SMS from ${event.From}. Forwarding via SMS to ${forwardSMSNumber}.`);
const msg = `New text from ${event.From}:\n\n${event.Body}`;
twiml.message({ to: forwardSMSNumber }, msg);
}
if (forwardDiscordURL !== "") {
await log(`Receiving SMS from ${event.From}. Forwarding via Discord to configured SMS webhook.`);
const msg = `New text from **${event.From}**\n>>> ${event.Body}`
try {
await axios.post(forwardDiscordURL, { content: msg });
} catch (err) {
console.error(`Error forwarding SMS to Discord: ${err}`);
}
}
callback(null, twiml);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment