Indicador RC LED "Baño ocupado"

Quiero construir un pequeño indicador LED para la puerta de mi baño. La idea básica es que cuando una persona se sienta o se para al lado del inodoro, un pequeño transmisor lo señala de forma inalámbrica al diodo LED que está montado en el lado frontal de la puerta. El LED se enciende para que la siguiente persona que quiera entrar sepa que el lugar ocupado está ocupado. Cuando el huésped sale del baño, el transmisor vuelve a señalar que el LED debe apagarse. Se me ocurrió un plan para conectar el LED a una pequeña batería. El circuito tiene que funcionar como un interruptor de encendido/apagado. Junto al averiado habrá un circuito con una fotorresistencia (?) que puede ayudar a detectar a alguien junto al inodoro. El cambio en su corriente/voltaje activa el pequeño transmisor que envía un pulso simple (u otra señal simple), que el circuito LED podrá recibir, y luego cambia su estado.

Pero tengo algunas preguntas. ¿Usar la fotorresistencia es un buen plan? ¿Quizás hay una mejor solución de la que no tengo idea? ¿Qué tipo de señal debe producir el transmisor? ¿Qué sería mejor usar como circuito de interruptor en el lado del LED?

Me encantaría leer algunas sugerencias que puedan ayudarme con este proyecto.

Use una cerradura para la puerta del baño. ¿Qué pasa si la persona no está junto al sensor del inodoro, es decir, usando el baño?
Gran idea :) Aunque preferiría usar el LED. ¿Tal vez podría usar un detector de movimiento para la detección del baño combinado con el IR/fotorresistor para el inodoro?
La cerradura de una puerta no necesita pilas, no sufrirá condensación, se puede ver bajo la luz directa del sol y es infalible y se puede anular con las herramientas adecuadas. Si hay una solución que es obvia, entonces debería estar justificado no buscarla porque a la gente aquí le gusta dar respuestas que son potencialmente útiles para varias personas y, sin entender la justificación, es posible que no obtenga las mejores respuestas.
Presumiblemente, la persona dentro del baño necesitará encender la luz. Hay interruptores de luz disponibles con un pequeño indicador LED alimentado por la red eléctrica en el interior, que debería poder conectar para que cuando se encienda la luz del baño, también se encienda el LED. ¡Problema resuelto! Suponiendo que el interruptor esté fuera del baño, por supuesto.
En aplicaciones comerciales donde se necesita una indicación de ocupación (trenes o aviones, por ejemplo), utilizan un sistema que obtiene la información de ocupación del mecanismo de bloqueo. Entonces, cuando alguien cierra la puerta, el circuito se cierra y se enciende una luz. Puede hacer algo como esto incluso si usa una cerradura deslizante rudimentaria. Estará directamente en la puerta y no necesitará ningún dispositivo electrónico sofisticado, solo una fuente de alimentación, una resistencia y un LED. La parte sobre pararse al lado del inodoro, bueno, IR estaría bien, puedes tomar un ambientador de detección de movimiento y hackearlo para enviar la señal.

Respuestas (1)

Construí algo a lo largo de estas líneas. Es un sensor de puerta inalámbrico con un sensor magnético en un lado y un LED en el receptor. Convenientemente, tanto el sensor de la puerta como el receptor son idénticos en esquema, placa y firmware, excepto por un solo puente que indica qué papel desempeñará el receptor/sensor.

Este diseño utiliza un sensor de láminas, que es un sensor magnético que detecta la presencia de un imán en un par de pulgadas. Adjunto un imán a la parte inferior de la puerta y adjunto la placa del sensor a la parte inferior del marco de la puerta. Esto funciona en los retretes o en la propia puerta del baño.

Para ahorrar energía, el receptor se enciende durante 1/10 de segundo cada segundo. Eso significa que el receptor tendrá un retraso de 1 segundo, pero consume 1/10 de la energía. Puede ajustar fácilmente estos números en función de la poca potencia que desea que use el receptor y la cantidad de retraso que está dispuesto a tolerar.

El control remoto usa interrupciones de cambio de pin de hardware, por lo que solo usa energía cuando transmite. Eso significa que puede funcionar con una sola batería de celda de moneda durante meses.

Aquí está el esquema:

Esquemático

Este esquema permite una batería de celda de moneda CR2032 o un conector de batería JST de 2 pines (usado para paquetes de baterías AA y LiPo). Utiliza el IC inalámbrico nRF24L01, que está fácilmente disponible.

El código fuente y los archivos EAGLE están disponibles en https://github.com/samuelclay/doormonitor Aquí está el código fuente del firmware. Las bibliotecas y las dependencias están vinculadas arriba, pero esta es la rutina principal.

#include <avr/sleep.h> 
#include <avr/interrupt.h> 
#include <avr/wdt.h>

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <pinchange.h>

void sleepNow(void);
void wakeup();
void setupWatchdog(uint8_t prescalar);

#if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__)
    RF24 radio(3,7);
    const int role_pin = 10;
    const int sensor_pin = 2;
    const int led_pin = 1;
    // const int sensor_pin = 8;
    // const int led_pin = 9;
#else
    RF24 radio(9, 10);
    const int role_pin = 6;
    const int sensor_pin = 2;
    const int led_pin = 4;
#endif 

const uint64_t pipe = 0xA8E8F0F0F1LL;

typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, 
               wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;

typedef enum { 
    role_remote = 1, 
    role_led = 2
} role_e;
role_e role;
const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"};

uint8_t led_state = 0;
uint8_t sensor_state = 0;
volatile int awakems = 0;
int send_tries = 0;
bool send_ok = false;

void setup(void) {
    // set up the role pin
    pinMode(role_pin, INPUT);
    digitalWrite(role_pin, HIGH);
    delay(20); // Just to get a solid reading on the role pin

    // read the address pin, establish our role
    role = digitalRead(role_pin) ? role_remote : role_led;
    digitalWrite(role_pin, LOW);

    Serial.begin(9600);

    radio.begin();
    radio.setChannel(38);
    radio.setDataRate(RF24_250KBPS);
    radio.setAutoAck(pipe, true);
    radio.setRetries(15, 15);

    if (role == role_remote) {
        radio.openWritingPipe(pipe);
        radio.stopListening();
    } else {
        radio.openReadingPipe(1,pipe);
        radio.startListening();
    }

//    radio.printDetails();

    if (role == role_remote) {
        pinMode(sensor_pin,INPUT);
        digitalWrite(sensor_pin,HIGH);
    }

    if (role == role_led) {
        setupWatchdog(wdt_2s);
    }

    pinMode(led_pin,OUTPUT);
    led_state = LOW;
    digitalWrite(led_pin, led_state);
    int i = role == role_led ? 4 : 2;
    int pause = role == role_led ? 100 : 300;
    while (i--) {
        delay(pause);
        digitalWrite(led_pin, HIGH);
        delay(pause);
        digitalWrite(led_pin, LOW);
    }
}

void loop(void) {
    bool different = false;

    if (role == role_remote) {
        // Get the current state of buttons, and
        // Test if the current state is different from the last state we sent
        uint8_t state = !digitalRead(sensor_pin);
        Serial.write("Sensor state: ");
        Serial.write(state ? "ON" : "off");
        Serial.write('\n');
        if (state != sensor_state) {
            different = true;
            send_tries = 1000;
            sensor_state = state;
            led_state = sensor_state;
        }

        // Send the state of the buttons to the LED board
        if (send_tries && (different || !send_ok)) {
            Serial.write("Now sending...");
            digitalWrite(led_pin, led_state);
            radio.powerUp();
            delay(10);
            send_ok = radio.write( &sensor_state, sizeof(uint8_t) );
            if (send_ok) {
                Serial.write("ok\n\r");
            } else {
                char tries_left_char[1];
                send_tries--;
                itoa(send_tries, tries_left_char, 10);
                Serial.write("failed (");
                Serial.write((char *)tries_left_char);
                Serial.write(" tries left)\n\r");
                digitalWrite(led_pin, LOW);
                delay(25);        
                digitalWrite(led_pin, led_state);            
            }
            radio.powerDown();
            awakems = 0;
        }

        awakems += 1;
        if (awakems > 10) {
            sleepNow();
            awakems = 0;
        }
    }

    if (role == role_led) {
         // digitalWrite(led_pin, HIGH);

        if (radio.available()) {
            // Dump the payloads until we've gotten everything
            bool done = false;
            awakems = 0;
            while (!done) {
                done = radio.read( &sensor_state, sizeof(uint8_t) );
            }
            Serial.write("Got buttons: ");
            Serial.write(sensor_state ? "ON\n\r" : "off\n\r");
            led_state = sensor_state;
            digitalWrite(led_pin, led_state);
            awakems = -10000;
        }

        uint8_t incomingByte;
        // send data only when you receive data:
        if (Serial.available() > 0) {
            // read the incoming byte:
            incomingByte = Serial.read();

            // say what you got with both the ASCII and decimal representations
            Serial.print("I received: ");
            Serial.write(incomingByte);
            Serial.print(" : ");
            Serial.println(incomingByte, DEC);

            awakems = 0;
        }

        awakems += 1;
        if (awakems > 4000) {
            // digitalWrite(led_pin, LOW);
            sleepNow();
            awakems = 0;
        }
    }
}
#define BODS 7                   //BOD Sleep bit in MCUCR
#define BODSE 2                  //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;

void setupWatchdog(uint8_t prescalar) {
  prescalar = min(9,prescalar);
  uint8_t wdtcsr = prescalar & 7;
  if ( prescalar & 8 )
    wdtcsr |= _BV(WDP3);

  MCUSR &= ~_BV(WDRF);
  WDTCSR = _BV(WDCE) | _BV(WDE);
  WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
}

void sleepNow(void) {
    Serial.write("Sleeping...\n\r");
    if (role == role_led) {
        radio.stopListening();
    }
    radio.powerDown();

    if (role == role_remote) {
        attachPcInterrupt(sensor_pin, wakeup, CHANGE);
    }
    ACSR |= _BV(ACD);                         //disable the analog comparator
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();

    //turn off the brown-out detector.
    //must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD.
    //current while sleeping will be <0.5uA if BOD is disabled, <25uA if not.
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    cli();                         //wake up here, disable interrupts
    if (role == role_remote) {
        detachPcInterrupt(sensor_pin);
    }
    sleep_disable();               
    sei();                         //enable interrupts again (but INT0 is disabled from above)
    Serial.print("Wakeup...\n\r");
    if (role == role_led) {
      radio.startListening();
    }
    delay(5);
}

void wakeup() {
    awakems = 0;
}

ISR(WDT_vect) {
    awakems = 0;
}
Wow gracias. Me parece un proyecto muy interesante. Definitivamente lo investigaré. ¡Supongo que hará el trabajo!