sql_app: Split doors and monitors

A alot of interface and database boiler plate

Signed-off-by: HeshamTB <hishaminv@gmail.com>
This commit is contained in:
HeshamTB 2022-06-09 21:52:42 +03:00
parent a316374da6
commit dcd2ff5b89
6 changed files with 200 additions and 44 deletions

View File

@ -56,3 +56,13 @@ def valid_iot_token(token : str, db: Session):
mac_signed = payload.get("bluetooth_mac") mac_signed = payload.get("bluetooth_mac")
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed) device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed)
return device return device
def valid_monitor_token(token: str, db: Session):
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
except jwt.DecodeError:
return None
mac_signed = payload.get("bluetooth_mac")
monitor = crud.get_monitor_bluetooth(db, mac_signed)
return monitor

View File

@ -17,7 +17,7 @@ from warnings import warn
def get_user(db: Session, user_id: int) -> models.User: def get_user(db: Session, user_id: int) -> models.User:
return db.query(models.User).get(user_id) return db.query(models.User).get(user_id)
def get_iot_entity(db: Session, id: int): def get_iot_entity(db: Session, id: int) -> models.IotEntity:
return db.query(models.IotEntity).get(id) return db.query(models.IotEntity).get(id)
def get_iot_entity_by_description(db: Session, description: str): def get_iot_entity_by_description(db: Session, description: str):
@ -44,8 +44,12 @@ def get_access_log_for_door_by_door_mac(db: Session, iot_id: str):
def get_access_log_for_user_by_id(db: Session, id : str): def get_access_log_for_user_by_id(db: Session, id : str):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == id).all() return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == id).all()
def get_room_data_now(db: Session) -> models.RoomSensorData: # def get_room_data_now(db: Session, door_id: int) -> models.RoomSensorData:
return db.query(models.RoomSensorData)[-1] # door = get_iot_entity(db, door_id)
# monitor : models.Monitors = door.monitor
# if not monitor: return -1
# if len(monitor.sensor_history) == 0: return -2
# return monitor.sensor_history[-1]
def create_user(db: Session, user: schemas.UserCreate): def create_user(db: Session, user: schemas.UserCreate):
key = crypto.gen_new_key(user.password) key = crypto.gen_new_key(user.password)
@ -73,6 +77,8 @@ def update_user_password(db: Session, user: models.User, request: schemas.UserUp
def get_iot_entities(db: Session, skip: int = 0, limit: int = 100): def get_iot_entities(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotEntity).offset(skip).limit(limit).all() return db.query(models.IotEntity).offset(skip).limit(limit).all()
def get_monitors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Monitors).offset(skip).limit(limit).all()
def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate): def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac, db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac,
@ -82,6 +88,37 @@ def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
db.refresh(db_item) db.refresh(db_item)
return db_item return db_item
def create_monitor(db: Session, monitor: schemas.IotEntityBase):
db_item = models.Monitors(bluetooth_mac=monitor.bluetooth_mac,
description=monitor.description)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def get_monitor(db: Session, id: int) -> models.Monitors:
return db.query(models.Monitors).get(id)
def get_monitor_bluetooth(db: Session, bluetooth_mac: str) -> models.Monitors:
return db.query(models.Monitors).filter(models.Monitors.bluetooth_mac == bluetooth_mac).first()
def update_monitor(db: Session, monitor: models.Monitors):
db.add(monitor)
db.commit()
db.refresh(monitor)
def update_monitor_readings(db: Session, monitor_upadte: schemas.MonitorUpdateReadings, bluetooth_mac: str):
monitor = get_monitor_bluetooth(db, bluetooth_mac)
monitor.humidity = monitor_upadte.humidity
monitor.people = monitor_upadte.people
monitor.smoke_sensor_reading = monitor_upadte.smoke_sensor_reading
monitor.temperature = monitor_upadte.temperature
db.add(monitor)
db.commit()
db.refresh(monitor)
def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int): def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
# Ensure link is not already present and it does not allow duplicates # Ensure link is not already present and it does not allow duplicates
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_id == iot_dev_id).first() link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_id == iot_dev_id).first()
@ -168,12 +205,14 @@ def record_door_access_log(db: Session, entry: schemas.DoorAccessLog):
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
def record_room_sensor_data(db: Session, entry: schemas.IotMonitorRoomInfo): def record_room_sensor_data(db: Session, entry: schemas.MonitorUpdateReadings,
monitor :models.Monitors):
db_item = models.RoomSensorData(humidity=entry.humidity, db_item = models.RoomSensorData(humidity=entry.humidity,
people=entry.people, people=entry.people,
temperature=entry.temperature, temperature=entry.temperature,
smoke_sensor_reading=entry.smoke_sensor_reading, smoke_sensor_reading=entry.smoke_sensor_reading,
timestamp=datetime.now()) timestamp=datetime.now(),
monitor_id=monitor.id)
db.add(db_item) db.add(db_item)
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
@ -190,9 +229,10 @@ def record_user_connection(db: Session, user: models.User, time: datetime):
db.commit() db.commit()
db.refresh(entry) db.refresh(entry)
def get_sensor_data_for_room(db: Session, skip: int = 0, limit: int = 100): # def get_sensor_data_for_room(db: Session, monitor_id: int, count_last: int):
data = db.query(models.RoomSensorData).offset(skip).limit(limit).all() # data = db.query(models.RoomSensorData).all()
return data # if not data or len(data) == 0: return -1
# return data[-count_last]
def update_user_status(db: Session, user: models.User, state: bool): def update_user_status(db: Session, user: models.User, state: bool):
user.is_active = state user.is_active = state

View File

@ -57,15 +57,15 @@ def init_door():
def init_monitor(): def init_monitor():
iot_monitor = schemas.IotEntityCreate(bluetooth_mac="ff:ff:00:ff", iot_monitor = schemas.IotEntityCreate(bluetooth_mac="ff:ff:00:ff",
description="Iot Lab Monitor") description="Iot Lab Monitor")
monitor_exists = crud.get_iot_entity_by_bluetooth_mac(db, iot_monitor.bluetooth_mac) monitor_exists = crud.get_monitor_bluetooth(db, iot_monitor.bluetooth_mac)
if monitor_exists: return if monitor_exists: return
crud.create_iot_entity(db, iot_monitor) crud.create_monitor(db, iot_monitor)
def init_allowance(): def init_allowance():
crud.create_user_link_to_iot(db, 1, 1) crud.create_user_link_to_iot(db, 1, 1)
def init_sensor_data(): def init_sensor_data():
monitor = crud.get_monitor(db, 1)
for i in range(50): for i in range(50):
room_data = \ room_data = \
schemas.\ schemas.\
@ -75,7 +75,7 @@ def init_sensor_data():
temperature=randint(18, 27), temperature=randint(18, 27),
smoke_sensor_reading=randint(150, 700), smoke_sensor_reading=randint(150, 700),
token='dummy') token='dummy')
crud.record_room_sensor_data(db, room_data) crud.record_room_sensor_data(db, room_data, monitor)
def init_open_close_requests(): def init_open_close_requests():
user = crud.get_user_by_email(db, "hisham@banafa.com.sa") user = crud.get_user_by_email(db, "hisham@banafa.com.sa")
@ -115,6 +115,11 @@ def init_user_connections():
crud.record_user_connection(db, users[i], datetime.now()) crud.record_user_connection(db, users[i], datetime.now())
crud.record_user_connection(db, users[i], datetime.now()) crud.record_user_connection(db, users[i], datetime.now())
def init_link_room_monitor():
monitor = crud.get_monitor(db, 1)
door = crud.get_iot_entity(db, 1)
monitor.door = door
crud.update_monitor(db, monitor)
def init(): def init():
init_user() init_user()
@ -124,4 +129,5 @@ def init():
init_sensor_data() init_sensor_data()
init_open_close_requests() init_open_close_requests()
init_user_connections() init_user_connections()
init_link_room_monitor()

View File

@ -135,22 +135,23 @@ def get_iot_access_list_for_user(db: Session = Depends(get_db), current_user: sc
user = crud.get_user_by_username(db, current_user.username) user = crud.get_user_by_username(db, current_user.username)
access_list = list() access_list = list()
for device in user.authorized_devices: for device in user.authorized_devices:
dev_db : models.IotEntity = device door : models.IotEntity = device
sensors = crud.get_room_data_now(db) monitor : models.Monitors = door.monitor
if not sensors: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, if not monitor: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link") detail="No Room link")
entry : schemas.RoomOverview = schemas.RoomOverview( entry : schemas.RoomOverview = schemas.RoomOverview(
id=dev_db.id, id=door.id,
description=dev_db.description, description=door.description,
bluetooth_mac=dev_db.bluetooth_mac, bluetooth_mac=door.bluetooth_mac,
open_request=dev_db.open_request, open_request=door.open_request,
time_seconds=dev_db.time_seconds, time_seconds=door.time_seconds,
acces_list_counter=dev_db.acces_list_counter, acces_list_counter=door.acces_list_counter,
humidity=sensors.humidity, humidity=monitor.humidity,
people=sensors.people, people=monitor.people,
temperature=sensors.temperature, temperature=monitor.temperature,
smoke_sensor_reading=sensors.smoke_sensor_reading, smoke_sensor_reading=monitor.smoke_sensor_reading,
force_close=dev_db.force_close force_close=door.force_close,
state=door.state
) )
access_list.append(entry) access_list.append(entry)
#crud.record_user_connection(db, user, datetime.now()) #crud.record_user_connection(db, user, datetime.now())
@ -191,12 +192,23 @@ def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit) iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
return iot_entities return iot_entities
@app.get("/admin/monitors/", response_model=List[schemas.Monitor], tags=['Admin'])
def read_iot_monitors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
monitors = crud.get_monitors(db, skip=skip, limit=limit)
return monitors
# TODO: Can duplicate # TODO: Can duplicate
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin']) @app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)): def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
iot_entities = crud.create_iot_entity(db, iot_entity) iot_entities = crud.create_iot_entity(db, iot_entity)
return iot_entities return iot_entities
@app.post("/admin/monitor/create", response_model=schemas.Monitor, tags=['Admin'])
def create_monitor(iot_entity: schemas.IotEntityBase,
db: Session = Depends(get_db)):
monitor = crud.create_monitor(db, iot_entity)
return monitor
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin']) @app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
def read_user(user_id: int, db: Session = Depends(get_db)): def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id) db_user = crud.get_user(db, user_id=user_id)
@ -275,13 +287,22 @@ def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
crud.update_user_status(db, user, True) crud.update_user_status(db, user, True)
@app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin']) @app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin'])
def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac, def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac):
api_key: APIKey = Depends(auth_helper.valid_api_key)): # api_key: APIKey = Depends(auth_helper.valid_api_key)
# We get here after a valid admin key, so send back permenant token # We get here after a valid admin key, so send back permenant token
data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac} data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac}
tkn = auth_helper.create_iot_dev_token(data) tkn = auth_helper.create_iot_dev_token(data)
return {"access_token": tkn, "token_type": "bearer"} return {"access_token": tkn, "token_type": "bearer"}
@app.patch("/admin/link/monitor/{monitor_id}/door/{door_id}", tags=['Admin'])
def link_monitor_with_door(monitor_id: int, door_id: int,
db: Session = Depends(get_db)):
monitor = crud.get_monitor(db, monitor_id)
door = crud.get_iot_entity(db, door_id)
monitor.door = door
crud.update_monitor(db, monitor)
return monitor
@app.post("/admin/user/accesslog/email/", tags=['Admin']) @app.post("/admin/user/accesslog/email/", tags=['Admin'])
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail, def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail,
db : Session = Depends(get_db)): db : Session = Depends(get_db)):
@ -296,14 +317,49 @@ def get_access_log_history_for_user(request : schemas.UserAccessLogRequestUserna
if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found") if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
return user.access_log return user.access_log
@app.get("/admin/roominfo/now/", tags=['Admin']) @app.get("/admin/roominfo/{door_id}/now", tags=['Admin'])
def get_room_data(db: Session = Depends(get_db)): def get_room_data(door_id: int, db: Session = Depends(get_db)):
return crud.get_room_data_now(db) door = crud.get_iot_entity(db, door_id)
if not door:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Door not found")
monitor : models.Monitors = door.monitor
if not monitor:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link")
data = monitor.sensor_history
if not data or len(data) == 0:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data[-1]
@app.get("/admin/roominfo/history/sensors", tags=['Admin']) @app.get("/admin/roominfo/{monitor_id}/now", tags=['Admin'])
def get_all_sensor_history(skip: int = 0, limit: int = 100, def get_room_data(monitor_id: int, db: Session = Depends(get_db)):
monitor = crud.get_monitor(db, monitor_id)
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Monitor not found")
if not monitor.door_id:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Monitor not linked")
data = crud.get_room_data_now(db, monitor.door_id)
if data == -1: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No Room link")
if data == -2: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data
@app.get("/admin/roominfo/{monitor_id}/last/{count}", tags=['Admin'])
def get_all_sensor_history(monitor_id: int, count: int,
db: Session = Depends(get_db)): db: Session = Depends(get_db)):
return crud.get_sensor_data_for_room(db, skip, limit) monitor = crud.get_monitor(db, monitor_id)
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Monitor not found")
data = monitor.sensor_history
if not data or len(data) == 0:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="No Sensor data")
return data[-count:]
@app.post("/admin/roominfo/accesslog",response_model=List[schemas.DoorAccessLog], tags=['Admin']) @app.post("/admin/roominfo/accesslog",response_model=List[schemas.DoorAccessLog], tags=['Admin'])
def get_access_log_for_door(request : schemas.AccessLogRequest, def get_access_log_for_door(request : schemas.AccessLogRequest,
@ -335,14 +391,14 @@ def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest,
return response return response
@app.post("/iotdevice/monitor/status", tags=['Iot']) @app.post("/iotdevice/monitor/status", tags=['Iot'])
def polling_method_for_room_monitor(request: schemas.IotMonitorRoomInfo, def polling_method_for_room_monitor(request: schemas.MonitorUpdateReadings,
db: Session = Depends(get_db)): db: Session = Depends(get_db)):
device : schemas.IotEntity = auth_helper.valid_iot_token(request.token, db) device : schemas.Monitor = auth_helper.valid_monitor_token(request.token, db)
if not device: if not device:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials") detail="Could not validate credentials")
crud.record_room_sensor_data(db, request) crud.record_room_sensor_data(db, request, device)
return request return request
@app.post("/iotdevice/door/users", response_class=PlainTextResponse, tags=['Iot']) @app.post("/iotdevice/door/users", response_class=PlainTextResponse, tags=['Iot'])
@ -376,3 +432,9 @@ def get_allowed_usernames(request: schemas.IotDoorPollingRequest,
tkns = tkns + db_user.last_token + '\n' tkns = tkns + db_user.last_token + '\n'
return tkns return tkns
@app.get("/test")
def get(db: Session = Depends(get_db)):
mon = crud.get_monitor(db, "ff:ff:ff:ff")
return mon.door

View File

@ -23,7 +23,7 @@ class IotEntity(Base):
__tablename__ = "iot_entities" __tablename__ = "iot_entities"
id = Column(Integer, primary_key=True, index=True) id = Column(Integer, primary_key=True, index=True)
bluetooth_mac = Column(String(512)) bluetooth_mac = Column(String(512), index=True, unique=True)
description = Column(String(512)) description = Column(String(512))
open_request = Column(Boolean, default=False) open_request = Column(Boolean, default=False)
time_seconds = Column(Integer, default=10) time_seconds = Column(Integer, default=10)
@ -31,7 +31,22 @@ class IotEntity(Base):
force_close = Column(Boolean, default=False) force_close = Column(Boolean, default=False)
state = Column(Boolean, default=False) # True is open, False is closed state = Column(Boolean, default=False) # True is open, False is closed
authorized_users = relationship("User", secondary="user_iot_link", back_populates="authorized_devices") authorized_users = relationship("User", secondary="user_iot_link", back_populates="authorized_devices")
access_log = relationship("DoorAccessLog", back_populates="iot_device") access_log = relationship("DoorAccessLog", back_populates="iot_device") # one-to-many
monitor = relationship("Monitors", back_populates="door", uselist=False) # one-to-one
class Monitors(Base):
__tablename__ = "monitors"
id = Column(Integer, primary_key=True)
bluetooth_mac = Column(String(512), index=True, unique=True)
description = Column(String(512))
humidity = Column(Integer, default=0)
people = Column(Integer, default=0)
temperature = Column(Integer, default=0)
smoke_sensor_reading = Column(Integer, default=0)
door_id = Column(Integer, ForeignKey("iot_entities.id"))
door = relationship("IotEntity", back_populates="monitor")
sensor_history = relationship("RoomSensorData", back_populates="monitor")
class UserAuthToIoTDev(Base): class UserAuthToIoTDev(Base):
__tablename__ = "user_iot_link" __tablename__ = "user_iot_link"
@ -61,6 +76,8 @@ class RoomSensorData(Base):
temperature = Column(Integer) temperature = Column(Integer)
smoke_sensor_reading = Column(Integer) smoke_sensor_reading = Column(Integer)
timestamp = Column(DateTime) timestamp = Column(DateTime)
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
monitor = relationship("Monitors", back_populates="sensor_history")
class UserConnectionHistory(Base): class UserConnectionHistory(Base):
__tablename__ = "user_connection_history" __tablename__ = "user_connection_history"

View File

@ -28,12 +28,33 @@ class IotEntity(IotEntityBase):
time_seconds: int time_seconds: int
force_close: bool force_close: bool
acces_list_counter: int acces_list_counter: int
state: bool
class Config: class Config:
orm_mode = True orm_mode = True
class IotBluetoothMac(BaseModel): class IotBluetoothMac(BaseModel):
bluetooth_mac : str bluetooth_mac : str
class Monitor(IotEntityBase):
# bluetooth_mac: str
# description: str
id: int
bluetooth_mac: str
description: str
humidity: int
people: int
temperature: int
smoke_sensor_reading: int
class Config:
orm_mode = True
class MonitorUpdateReadings(BaseModel):
humidity : int
people : int
temperature : int
smoke_sensor_reading : int
token: str # Contains mac
class User(UserBase): class User(UserBase):
id: int id: int
is_active: bool is_active: bool
@ -90,8 +111,8 @@ class IotMonitorRoomInfo(BaseModel):
temperature : int temperature : int
smoke_sensor_reading : int smoke_sensor_reading : int
token: str token: str
class Config: # class Config:
orm_mode = True # orm_mode = True
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo): class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
time: datetime time: datetime