from machine import UART, Pin, PWM, time_pulse_us, ADC
import time, math, dht, neopixel
#############################
######## Assumptions ########
#############################
garage_capacity = 8
parking_occupancy = 0
garage_entry_time = 30000 # 30 second
##############################
###### Pin Configuration #####
##############################
# ---- System 01: ----
trigger_pin = 32
echo_pin = 35
green_01_pin = 26
red_01_pin = 27
buzzer_pin = 33
servo_pin = 25
# ---- System 02: ----
clk_pin = 22
dt_pin = 23
segmant_pins_nums = {
"A": 17,
"B": 16,
"C": 14,
"D": 12,
"E": 0,
"F": 13,
"G": 1,
}
# ---- System 03: ----
dht_pin = 5
mq2_pin = 34
# ---- System 04: ----
pir_pin = 18
LDR_pin = 36
parking_lights_pin = 15
dir_pin, step_pin = 19, 21
# ---- System 05: ----
neopixel_pin = 4
emergency_buzzer_pin = 2
# ---- System 06: ----
dashboard_btn_pin = 39
#############################
### Initialize Components ###
#############################
# ---- System 01: ----
vehicle_detected = False
barrier_opening_time = last_get_distance = time.ticks_ms()
consecutive_reads = 0
trigger = Pin(trigger_pin, Pin.OUT)
echo = Pin(echo_pin, Pin.IN)
green_01_led = Pin(green_01_pin, Pin.OUT, value=0)
red_01_led = Pin(red_01_pin, Pin.OUT, value=1)
buzzer = PWM(Pin(buzzer_pin))
buzzer.freq(440)
buzzer.deinit()
servo_motor = PWM(Pin(servo_pin), duty=25)
servo_motor.freq(50)
# ---- System 02: ----
start = time.ticks_ms()
segmant_pins = {
seg: Pin(seg_num, Pin.OUT) for seg, seg_num in segmant_pins_nums.items()
}
segmants_order = ["A", "B", "C", "D", "E", "F", "G"]
HEX_MAP = {
0: 0x3F, # 00111111
1: 0x06, # 00000110
2: 0x5B, # 01011011
3: 0x4F, # 01001111
4: 0x66, # 01100110
5: 0x6D, # 01101101
6: 0x7D, # 01111101
7: 0x07, # 00000111
8: 0x7F, # 01111111
9: 0x6F, # 01101111
}
clk = Pin(clk_pin, Pin.IN, Pin.PULL_UP)
dt = Pin(dt_pin, Pin.IN, Pin.PULL_UP)
last_clk_value = clk.value()
# ---- System 03: ----
light_status = ""
last_sample_time = time.ticks_ms()
sample_interval = 500
air_quality_history = []
dht_sensor = dht.DHT22(Pin(dht_pin, Pin.IN))
mq2_adc = ADC(Pin(mq2_pin))
mq2_adc.atten(ADC.ATTN_11DB)
# Defults
temperature = 24.0
temp_status = "Normal"
smoothed_air_quality = 0
air_status = "Good"
# ---- System 04: ----
last_motion_time = time.ticks_ms()
lights_on = False
motion_hold_ms = 20000
light_precentage = 0
pir_sensor = Pin(pir_pin, Pin.IN)
last_light_check = time.ticks_ms()
light_check_interval = 500
last_step_time = time.ticks_ms()
step_state = 0
step_speed_delay_us = 2000
LDR_adc = ADC(Pin(LDR_pin))
LDR_adc.atten(ADC.ATTN_11DB)
parking_lights = PWM(Pin(parking_lights_pin))
parking_lights.freq(1000)
stepper_dir = Pin(dir_pin, Pin.OUT, value=0)
stepper_step = Pin(step_pin, Pin.OUT)
ventilation_table = {
("Normal", "Good"): "OFF",
("Normal", "Moderate"): "LOW",
("Normal", "Poor"): "HIGH",
("High", "Good"): "LOW",
("High", "Moderate"): "MEDIUM",
("High", "Poor"): "HIGH",
("Critical", "Good"): "HIGH",
("Critical", "Moderate"): "HIGH",
("Critical", "Poor"): "HIGH",
}
# ---- System 05: ----
prev_status = "Normal"
last_flash_time = time.ticks_ms()
flash_state = False
np_ring = neopixel.NeoPixel(Pin(neopixel_pin), 16)
last_buzzer_time = time.ticks_ms()
buzzer_state = False
emergency_buzzer = PWM(Pin(emergency_buzzer_pin))
emergency_buzzer.deinit()
# ---- System 06: ----
last_btn_state = time.ticks_ms()
last_debounce_time = time.ticks_ms()
dashboard_btn = Pin(dashboard_btn_pin, Pin.IN)
#############################
######### Functions #########
#############################
def get_distance_cm():
# 1. Ensure trigger is low first
trigger.value(0)
time.sleep_us(2)
# 2. Send a 10 microsecond pulse to trigger a reading
trigger.value(1)
time.sleep_us(10)
trigger.value(0)
# 3. Measure the duration of the HIGH pulse on the Echo pin
# 30000 microseconds is the timeout limit (1 second)
pulse_duration = time_pulse_us(echo, 1, 30000)
# If it timed out or errored, return an error flag (-1)
if pulse_duration < 0:
return -1
# 4. Calculate distance in cm based on speed of sound
distance = (pulse_duration * 0.0343) / 2
return distance
def open_barrier():
# 1. Move Servo mottor
servo_motor.duty(75)
# 2. Adjust the lights
green_01_led.value(1)
red_01_led.value(0)
# 3. Turn on The Buzzer
buzzer.init()
buzzer.duty(512)
def close_barrier():
# 1. Move Servo mottor
servo_motor.duty(25)
# 2. Adjust the lights
green_01_led.value(0)
red_01_led.value(1)
# 3. Turn Off The Buzzer
buzzer.deinit()
def display_num(number):
hex_pattern = HEX_MAP[number]
for bit_index, seg in enumerate(segmants_order):
bit_state = (hex_pattern >> bit_index) & 1
segmant_pins[seg].value(1- bit_state)
def set_safety_ring(color):
for i in range(16):
np_ring[i] = color
np_ring.write()
def log():
print("\n\n=== SYSTEM DASHBOARD & REPORTING ===")
print(f"Parking Occupancy: {parking_occupancy}/{garage_capacity}")
print(f"Ambient Light Percentage: {light_precentage}%, Status={light_status}")
print(f"Environmental Status: Temp={temperature:.1f}C, Status={temp_status}")
print(f"Air Quality Value: {smoothed_air_quality:.0f}, Status={air_status}")
print(f"Safety Status Code: {active_hazards} Active Hazards")
print("=====================================")
#############################
display_num(parking_occupancy)
#############################
#############################
######### Main Loop #########
#############################
while True:
current = time.ticks_ms()
current_us = time.ticks_us()
# ---- System 01: ----
if vehicle_detected and parking_occupancy < garage_capacity:
if time.ticks_diff(current, barrier_opening_time) <= garage_entry_time:
open_barrier()
else:
close_barrier()
barrier_opening_time = current
vehicle_detected = False
consecutive_reads = 0
else:
if time.ticks_diff(current, last_get_distance) >= 200:
distance = get_distance_cm()
if distance > 0 and distance <= 400:
if distance <= 100:
consecutive_reads += 1
else:
consecutive_reads = 0
last_get_distance = current
if consecutive_reads == 2:
vehicle_detected = True
barrier_opening_time = current
close_barrier()
# ---- System 02: ----
current_clk_state = clk.value()
if current_clk_state != last_clk_value:
if current_clk_state == 0:
if time.ticks_diff(current, start) > 5:
# read direction
if current_clk_state != dt.value():
if parking_occupancy < garage_capacity:
parking_occupancy += 1
vehicle_detected = False
else:
if parking_occupancy > 0:
parking_occupancy -= 1
display_num(parking_occupancy)
start = current
last_clk_value = current_clk_state
# ---- System 03: ----
if time.ticks_diff(current, last_sample_time) >= sample_interval:
try:
dht_sensor.measure()
temperature = dht_sensor.temperature()
humidity = dht_sensor.humidity()
# Fallback values if the simulator drops a packet frame
except OSError as e:
temperature = 24.0
humidity = 50.0
if temperature > 45.0:
temp_status = "Critical"
elif temperature >= 35.0:
temp_status = "High"
else:
temp_status = "Normal"
air_quality_history.append(mq2_adc.read())
if len(air_quality_history) > 5:
air_quality_history.pop(0)
smoothed_air_quality = sum(air_quality_history) / len(air_quality_history)
if smoothed_air_quality > 2200:
air_status = "Poor"
elif smoothed_air_quality >= 1200:
air_status = "Moderate"
else:
air_status = "Good"
last_sample_time = current
# ---- System 04: ----
if pir_sensor.value() == 1:
last_motion_time = current
motion_active = time.ticks_diff(current, last_motion_time) < motion_hold_ms
if time.ticks_diff(current, last_light_check) >= light_check_interval:
light_value = LDR_adc.read()
pwm_duty = int((light_value / 4095) * 1023)
if pwm_duty > 1023: pwm_duty = 1023
elif pwm_duty < 0: pwm_duty = 0
light_precentage = int((pwm_duty / 1023) * 100)
if light_precentage < 20:
light_status = "Dark"
elif light_precentage < 50:
light_status = "Dim"
else:
light_status = "Bright"
if light_status == "Bright":
lights_on = False
elif motion_active and light_status in ("Dim", "Dark"):
lights_on = True
elif not motion_active:
lights_on = False
parking_lights.duty(1023 if lights_on else 0)
last_light_check = current
fan_level = ventilation_table[(temp_status, air_status)]
if fan_level == "OFF":
stepper_step.value(0)
else:
delay_map = {"LOW": 4000, "MEDIUM": 2000, "HIGH": 800} # tune as needed
step_speed_delay_us = delay_map[fan_level]
if time.ticks_diff(current_us, last_step_time) >= step_speed_delay_us:
step_state = 1 if step_state == 0 else 0
stepper_step.value(step_state)
last_step_time = current_us
# ---- System 05: ----
active_hazards = 0
hazard_causes = []
if temp_status == "Critical":
active_hazards += 1
hazard_causes. append("Critical Temperature")
if air_status == "Poor":
active_hazards += 1
hazard_causes. append("Poor Air Quality")
if parking_occupancy >= int(0.8 * garage_capacity):
active_hazards += 1
hazard_causes.append("Parking Occupancy ≥ 80%")
status = ["Normal", "Warning", "Emergency"][active_hazards if active_hazards < 3 else 2]
if status == "Normal":
set_safety_ring((0, 255,0))
buzzer_state = False
elif status == "Warning":
set_safety_ring((255, 255,0))
buzzer_state = False
else:
if time.ticks_diff(current, last_flash_time) >= 500:
flash_state = not flash_state
if flash_state:
set_safety_ring((255, 0,0))
else:
set_safety_ring((0, 0,0))
last_flash_time = current
if time.ticks_diff(current, last_buzzer_time) >= 250:
buzzer_state = not buzzer_state
if buzzer_state:
emergency_buzzer.init()
emergency_buzzer.freq(1000)
emergency_buzzer.duty(512)
else:
emergency_buzzer.deinit()
last_buzzer_time = current
if status == "Emergency" and status != prev_status:
log()
print("\n-- Emergency Reasons:")
for cause in hazard_causes:
print(f"{hazard_causes.index(cause) + 1}. {cause}")
prev_status = status
else:
prev_status = status
# ---- System 06: ----
current_btn_reading = dashboard_btn.value()
if time.ticks_diff(current, last_debounce_time) >= 100:
if current_btn_reading != last_btn_state:
if current_btn_reading == 1:
log()
last_btn_state = current_btn_reading
last_debounce_time = current
======= SYSTEM 01: =======
SYSTEM 02:
SYSTEM 02:
SYSTEM 03:
Fan