I’m using the pulseIn
method to check if a dial tone is being send to the handset of an intercom.
Most of the time the line it’s reading is at 0V, so the method call takes until the set timeout of 3 seconds.
I’m finding that when making the call to this method inside loop
that the the device keeps disconnecting and reconnecting to the cloud. It’d doesn’t look to lose the WiFi connection.
Here’s the current firmware:
// Pin to ground the door release line.
int DR = D4;
// Pins to ground the microphone and speaker lines.
int S1 = D6;
int S2 = D5;
// Pin to monitor the call tone line.
int BZ = A1;
// The current state of the handset.
bool handsetNotificationSent = false;
bool handsetActive = false;
// The time we last checked the handset was active.
int lastHandsetCheck = 0;
// The time that the system was last primed.
int lastPrimed = 0;
// Specify the antenna to use for WiFi.
// @see https://docs.particle.io/reference/firmware/photon/#selectantenna-
// STARTUP(WiFi.selectAntenna(ANT_EXTERNAl));
// Danger Zone.
SYSTEM_THREAD(ENABLED);
void setup()
{
Particle.function("doorOpen", doorOpen);
Particle.function("primeSystem", primeSystem);
// Setup the relay signals.
pinMode(DR, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
// System primed indicator.
pinMode(D7, OUTPUT);
// Setup the BZ line to read the call tone with `pulseIn`.
pinMode(BZ, INPUT_PULLDOWN);
// Initalise the output pins.
digitalWrite(DR, LOW);
digitalWrite(S1, LOW);
digitalWrite(S2, LOW);
digitalWrite(D7, LOW);
}
void loop()
{
handsetActive = isHandsetActive();
// Send an event for the current activation, if we haven't already.
if (! handsetNotificationSent && handsetActive) {
handsetNotificationSent = Particle.publish("handset-activated", NULL, 60, PRIVATE);
}
// Reset the notification global variable if the handset's no longer active after we've sent a notification.
if (handsetNotificationSent && ! handsetActive) {
handsetNotificationSent = false;
}
// Can we automatically unlock the door?
if (handsetActive && isSystemPrimed()) {
// Open the door!
doorOpen("automatically");
// Make prime a one use method.
unprimeSystem("unlocked");
}
// Unprime the system if has timed-out.
if (! isSystemPrimed()) {
unprimeSystem("timeout");
}
// Reboot the device if it's been on for more than a day and it's around midnight.
if (Time.hour() >= 1 && millis() > 86400000) {
System.reset();
}
}
/**
* Unprime the system for the given reason.
*/
void unprimeSystem(String reason)
{
if (lastPrimed != 0) {
// Turn off the primed status visual indicator.
digitalWrite(D7, LOW);
// Publish why the system is now not primed.
Particle.publish("system-unprimed", reason, 60, PRIVATE);
// Reset the global timestamp.
lastPrimed = 0;
}
}
/**
* Prime the system.
*
* Allows us to check in the loop if we're allowed to automatically
* open the door when the handset is called.
*/
int primeSystem(String command)
{
// Update the last primed global variable.
lastPrimed = Time.now();
// Let's add a visual indicator that the system is primed.
digitalWrite(D7, HIGH);
Particle.publish("system-primed", NULL, 60, PRIVATE);
return 0;
}
/**
* Open the door!
*/
int doorOpen(String command)
{
// If the handset is not active we can't open the door.
if (! handsetActive) {
return -1;
}
// "Pickup" the handset and "press" the door release button.
digitalWrite(S1, HIGH);
digitalWrite(S2, HIGH);
digitalWrite(DR, HIGH);
delay(100);
// Finally resetting all the relays.
digitalWrite(DR, LOW);
digitalWrite(S1, LOW);
digitalWrite(S2, LOW);
Particle.publish("door-unlocked", (command != "") ? command : "manually", 60, PRIVATE);
return 0;
}
/**
* Check if the system is currently in a "primed" state.
*/
bool isSystemPrimed()
{
return (lastPrimed > Time.now() - 60 * 3);
}
/**
* Check if the handset is current being called.
*
* Slow function, will take up to 3 seconds to return if there is no pulse to read.
*/
bool isHandsetActive()
{
// When active the BZ line should have a voltage between 0V and 2.5V as a square wave.
// @see https://docs.particle.io/reference/firmware/photon/#pulsein-.
return (pulseIn(BZ, HIGH) > 0);
}
I’ve also tried (perhaps naively) putting the call in a thread that I kick off in start
.
Having system threading enabled doesn’t seem to make a difference.
Would love any suggestions! Otherwise I’ll look to open a PR to pass in a timeout to pulseIn
.