Cherokee HallJoshua WoodsJack Donoghue
Published

Proximity Bike Lock

The proximity motorcycle lock can lock/unlock itself when the user is within a certain distance and inform them of prime riding conditions.

IntermediateFull instructions providedOver 1 day604
Proximity Bike Lock

Things used in this project

Hardware components

Argon
Particle Argon
×3
Breadboard (generic)
Breadboard (generic)
×3
OLED Screen
×1
Temperature and Humidity Sensor
×1
PIR Infrared Sensor (Motion Sensor)
×1
Linear Actuator
×1
Forward and Reverse Relay Module Controller (H Bridge)
×1
12 V AA Battery Housing
×1
LED (generic)
LED (generic)
×2
Dupont Wires
×1
Songhe DC 1 Channel Optocoupler 3V/3.3V Relay
×1
AA Batteries
AA Batteries
×8

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE
ThingSpeak API
ThingSpeak API

Story

Read more

Schematics

Sensor Cluster

Temperature Sensor Utilized Only Had Three Pins

OLED Beacon (Remote)

Locking Mechanism

-FRM 050 Represents the H-Bridge Which Controls Forward and Reverse Motion.
-Motor Represents the Linear Actuator
-Red LED (Realistically Green) Utilized for Two-Way Communication

Code

Sensor Cluster

C/C++
// This #include statement was automatically added by the Particle IDE.
#include <ThingSpeak.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>

// This example assumes the sensor to be plugged into CONN2
#define DHTPIN 2     // what pin we're connected to

// Here we define the type of sensor used
#define DHTTYPE DHT11        // DHT 11 
int TemperatureRead = 0; //define integer for later use in Particle Subscribe

int currentTemp = 0; //define integer for current temperature reading

int currentHumid = 0; //define integer for current humidity reading

int LED = D6; //define integer for LED to corresponding Argon Pin

int val; //define integer for variable to correspond to Motion Sensor Detection

DHT dht(DHTPIN, DHTTYPE);

TCPClient client;

unsigned long lastcheck = 0; //variable to define time between Temperature and Humidity Checks

unsigned long myChannelNumber = 1571524;
const char * myWriteAPIKey = "VWUUI86CR774ZEC6"; //inputs for ThingSpeak channel

int checkhandler(String command) { //code for temperature and humidity checks
    checktemp();
    checkhumid();
    
    return 1;
}

void checktemp() { //measure and publish temperature measurement
    currentTemp=(int)dht.getTempFarenheit();
    if (currentTemp>0) {
        Particle.publish("currentTemp", String(currentTemp), PRIVATE);
    }
}

void checkhumid() { //measure humidity
    currentHumid=(int)dht.getHumidity();
    
}

void setup() { 
    ThingSpeak.begin(client); //Begin ThingSpeak
    dht.begin(); 
    Serial.begin(9600); 
    pinMode(LED, OUTPUT); //set mode of pin D6 as Output
    pinMode(D4, INPUT); //set mode of pin D4 as Input for Motion Detection
    
    checktemp(); //code to check temperature
    Particle.variable("temp", currentTemp); //define variable to check temperature and humidity on particle console
    Particle.variable("humid", currentHumid);
    
    Particle.function("checktemp", checkhandler); //function to be able to check temperature and humidity via particle console
    Particle.function("checkhumid", checkhandler);
    
    Particle.subscribe("TemperatureRead",led, MY_DEVICES); //subscribe to event to confirm temperature readings was read
}

void led(const char *event, const char *data) { //blink LED to confirm temperature reading
    digitalWrite(LED, HIGH);
    delay(1000);
    digitalWrite(LED, LOW);
}

void loop() {
    unsigned long currentMillis = millis(); //define time in milliseconds
    
    val = digitalRead(D4); //read pin D4
    
    if (val == HIGH) {
        Particle.publish("motion", "motion detected", PRIVATE); //publish event when motion is detected
    }
    
    if (currentMillis-lastcheck > 10000) { //check temperature and humidity based on last check
        lastcheck=currentMillis;
        
        checktemp();
        checkhumid();
        
    }
    
    if (currentTemp>0) { //filter to not publish sensor misreadings to ThingSpeak
        ThingSpeak.setField(1,currentTemp);
        Serial.print(dht.getTempFarenheit());
        Serial.println("currentTemp");
        ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);  
        delay(16000); // ThingSpeak will only accept updates every 15 seconds.
    }
    
    if (currentHumid>0) {
        ThingSpeak.setField(2,currentHumid);
        Serial.print(dht.getHumidity());
        Serial.println("currentHumid");
        ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);  
        delay(16000); // ThingSpeak will only accept updates every 15 seconds. 
    }
    
}

OLED Beacon (Remote)

C/C++
// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_SSD1306.h>

// This #include statement was automatically added by the Particle IDE.

#include "Particle.h"

SerialLogHandler logHandler(LOG_LEVEL_TRACE);

const uint32_t myColor = 0xff0000;
// 0xff0000 = red
// 0x00ff00 = green
// 0x0000ff = blue

void setAdvertisingData();

#define OLED_SCL    D1
#define OLED_SDA  D0

int TemperatureRead = 1;
char currentTemp[9]; 
String currentTemp0;




Adafruit_SSD1306 display(-1);

void setup()  
{
   Serial.begin(9600);
   pinMode(D4, OUTPUT);
   
    Serial.println(F("OLEDisplay 128x64"));
    Particle.subscribe("currentTemp", HAT, MY_DEVICES);//Subscribes to the HAT Particle Argon to receive the temperature readings.
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    display.display();
    
    Particle.subscribe("unlock", anything, "e00fce6866adfe3d29154ce9");//Subscribes to the unlock function of the Locking Mechanism Particle Argon
    Particle.subscribe("lock", lockmech, "e00fce6866adfe3d29154ce9");//Subscribes to the lock function of the Locking Mechanism Particle Argon
    
    (void)logHandler; // Does nothing, just to eliminate the unused variable warning

    BLE.on();

    setAdvertisingData();

}


void anything(const char *event, const char *data)
{
    digitalWrite(D4, HIGH);//Signals LED on
    Particle.publish("Bluetoothsignal", "on", PRIVATE); //publish event to signal other Argon when Bluetooth is in proximity
}

void lockmech(const char *event, const char *data)
{
    digitalWrite(D4, LOW);//Signals LED off
}

void loop() 
{
   
    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0,0); 
    Time.zone(-5);
    display.print(Time.timeStr().c_str());//Displays accurate date and time
    display.setCursor(0,20);
 
    if (currentTemp>0); {
        
        display.setTextSize(2);
        display.setCursor(0,30);
        display.printf("Temp  %0.4s F", currentTemp);//Displays the temperature readings acquired by the HAT Particle Argon
    
    }
   
    
     display.display();
    delay(500);
    
}


void HAT(const char *event, const char *data)
{
    if (currentTemp>0) {
        strcpy(currentTemp,data);
        delay(3000);
        Particle.publish("TemperatureRead", String(TemperatureRead), PRIVATE); //Publishes TemperatureRead function for the Sensor Cluster to subscribe to. Turns on LED when OLED receives the temperature reading.
}

   }
   
   
   
   void setAdvertisingData() {
    uint8_t buf[BLE_MAX_ADV_DATA_LEN];

    size_t offset = 0;

    // Manufacturer-specific data
    // 16-bit: Company ID (0xffff)
    // Byte: Internal packet identifier (0x55)
    // 32-bit: Color code

    // Company ID (0xffff internal use/testing)
    buf[offset++] = 0xff;
    buf[offset++] = 0xff;

    // Internal packet type. This is arbitrary, but provides an extra
    // check to make sure the data is my data, since we use the 0xffff company
    // code.
    buf[offset++] = 0x55;

    // Our specific data, color code
    memcpy(&buf[offset], &myColor, 4);
    offset += 4;

    BleAdvertisingData advData;
    advData.appendCustomData(buf, offset);

    // Advertise every 100 milliseconds. Unit is 0.625 millisecond intervals.
    BLE.setAdvertisingInterval(160);

    // Continuously advertise
    BLE.advertise(&advData);
}

Locking Mechanism

C/C++
#include "Particle.h"

// This example does not require the cloud so you can run it in manual mode or
// normal cloud-connected mode
// SYSTEM_MODE(MANUAL);

SerialLogHandler logHandler(LOG_LEVEL_TRACE);

const size_t SCAN_RESULT_MAX = 30;

BleScanResult scanResults[SCAN_RESULT_MAX];
LEDStatus ledOverride(RGB_COLOR_WHITE, LED_PATTERN_SOLID, LED_SPEED_NORMAL, LED_PRIORITY_IMPORTANT);

bool Unlock = false; //boolean for if statement to initiate publish event
bool Lock = false; //boolean for if statement to initiate publish event


void setup() {
	(void)logHandler; // Does nothing, just to eliminate the unused variable warning

	BLE.on();
    pinMode(D5, OUTPUT); //set D5 pin mode as output
    pinMode(D6, OUTPUT); //set D6 pin mode as output
    Particle.subscribe("Bluetoothsignal", LED, "e00fce68ed92efdad5e8ef3c"); //subscribe to event for 2-way communication
}

void LED(const char *event, const char *data)
{
    digitalWrite(D6, HIGH);//Signals LED on when in proximity
}

void loop() {
	// Only scan for 500 milliseconds
    
	BLE.setScanTimeout(2000);
	int count = BLE.scan(scanResults, SCAN_RESULT_MAX);

	uint32_t curColorCode;
	int curRssi = -999;
    
	for (int ii = 0; ii < count; ii++) {
		uint8_t buf[BLE_MAX_ADV_DATA_LEN];
		size_t len;

		// When getting a specific AD Type, the length returned does not include the length or AD Type so len will be one less
		// than what we put in the beacon code, because that includes the AD Type.
		len = scanResults[ii].advertisingData.get(BleAdvertisingDataType::MANUFACTURER_SPECIFIC_DATA, buf, BLE_MAX_ADV_DATA_LEN);
		if (len == 7) {
			// We have manufacturer-specific advertising data (0xff) and it's 7 bytes (without the AD type)

			// Byte: BLE_SIG_AD_TYPE_MANUFACTURER_SPECIFIC_DATA (0xff)
			// 16-bit: Company ID (0xffff)
			// Byte: Internal packet identifier (0x55)
			// 32-bit: Color code

			if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0x55) {
				// Company ID and internal packet identifier match

				uint32_t colorCode;
				memcpy(&colorCode, &buf[3], 4);

				Log.info("colorCode: 0x%lx rssi=%d address=%02X:%02X:%02X:%02X:%02X:%02X ",
						colorCode, scanResults[ii].rssi,
						scanResults[ii].address[0], scanResults[ii].address[1], scanResults[ii].address[2],
						scanResults[ii].address[3], scanResults[ii].address[4], scanResults[ii].address[5]);

				if (scanResults[ii].rssi > curRssi) {
					// Show whatever device has the strongest signal
					curRssi = scanResults[ii].rssi;
					curColorCode = colorCode;
					
				}
			}
		}
	}
	if (curRssi != -999) {
		ledOverride.setColor(curColorCode); //change LED on Argon depending on Bluetooth Signal
		ledOverride.setActive(true);
		digitalWrite(D5, LOW); //set pin D5 low to unlock the actuator
		delay(2000);
		if (Unlock == false) {
		    Particle.publish("unlock", "In Proximity", PRIVATE); //publish unlock event to signal other Argon to light LED
		    Unlock = true;
		    Lock = false;
		}
	}
	else {
		ledOverride.setActive(false); //change LED on Argon depending on Bluetooth Signal
		digitalWrite(D5, HIGH); //set pin D5 to HIGH to extend linear actuator
		if (Lock == false) {
		    Particle.publish("lock", "Out Proximity", PRIVATE); //publish lock event to signal other Argon to turn of LED
		    digitalWrite(D6, LOW); //turn  off LED when no bluetooth signal
		    Unlock = false;
		    Lock = true;
		}
	}
}

Credits

Cherokee Hall

Cherokee Hall

2 projects • 1 follower
Joshua Woods

Joshua Woods

1 project • 0 followers
Jack Donoghue

Jack Donoghue

1 project • 0 followers

Comments