Skip to content

Commit

Permalink
Merge pull request #84 from t0mer/database
Browse files Browse the repository at this point in the history
Add ability to save, manage and share codes
  • Loading branch information
t0mer authored Jul 21, 2024
2 parents 6d49fcd + 677972a commit d04e44a
Show file tree
Hide file tree
Showing 14 changed files with 844 additions and 21 deletions.
2 changes: 1 addition & 1 deletion broadlinkmanager/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.4.0
6.0.0
48 changes: 37 additions & 11 deletions broadlinkmanager/broadlinkmanager.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
# region Importing

import os
import json
import subprocess
import time
import broadlink
import argparse
import datetime
import re
import shutil
import uvicorn
import socket
import aiofiles
from code import Code
from os import environ, path
from json import dumps
from sqliteconnector import SqliteConnector
from broadlink.exceptions import ReadError, StorageError
from broadlink import exceptions as e
from broadlink.const import DEFAULT_BCAST_ADDR, DEFAULT_PORT, DEFAULT_TIMEOUT
Expand All @@ -38,13 +35,15 @@
from fastapi.encoders import jsonable_encoder
from starlette_exporter import PrometheusMiddleware, handle_metrics


# Use to disable Google analytics code
ENABLE_GOOGLE_ANALYTICS = os.getenv("ENABLE_GOOGLE_ANALYTICS")
# endregion

ip_format_regex = r"\b(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]))\b"


db = SqliteConnector()
db.create_tables()
logger.info("OS: " + os.name)

def validate_ip(ip):
Expand Down Expand Up @@ -430,6 +429,11 @@ def about(request: Request):
return templates.TemplateResponse('about.html', context={'request': request, 'analytics': analytics_code, 'version': GetVersionFromFle()})


@app.get('/saved', include_in_schema=False)
def about(request: Request):
return templates.TemplateResponse('saved.html', context={'request': request, 'analytics': analytics_code, 'version': GetVersionFromFle()})


@app.get('/temperature', tags=["Commands"], summary="Read Temperature")
def temperature(request: Request, mac: str = "", host: str = "", type: str = ""):
logger.info("Getting temperature for device: " + host)
Expand Down Expand Up @@ -460,10 +464,10 @@ def learnir(request: Request, mac: str = "", host: str = "", type: str = "", com
break
else:
logger.error("No IR Data")
return JSONResponse('{"data":"","success":0,"message":"No Data Received"}')
return JSONResponse('{"data":"","success":0,"message":"No Data Received","type":"ir"}')
learned = ''.join(format(x, '02x') for x in bytearray(data))
logger.info("IR Learn success")
return JSONResponse('{"data":"' + learned + '","success":1,"message":"IR Data Received"}')
return JSONResponse('{"data":"' + learned + '","success":1,"message":"IR Data Received","type":"ir"}')

# Send IR/RF

Expand Down Expand Up @@ -507,7 +511,7 @@ def sweep(request: Request, mac: str = "", host: str = "", type: str = "", comma
logger.error("Device:" + host + " RF Frequency not found!")
_rf_sweep_message = "RF Frequency not found!"
dev.cancel_sweep_frequency()
return JSONResponse('{"data":"RF Frequency not found!","success":0}')
return JSONResponse('{"data":"RF Frequency not found!","success":0,"type":"rf"}')

_rf_sweep_message = "Found RF Frequency - 1 of 2!"
logger.info("Device:" + host + " Found RF Frequency - 1 of 2!")
Expand Down Expand Up @@ -536,15 +540,15 @@ def sweep(request: Request, mac: str = "", host: str = "", type: str = "", comma
else:
logger.error("Device:" + host + " No Data Found!")
_rf_sweep_message = "No Data Found"
return JSONResponse('{"data":"No Data Found"}')
return JSONResponse('{"data":"No Data Found","type":"rf","type":"rf"}')

_rf_sweep_message = "Found RF Frequency - 2 of 2!"
logger.info("Device:" + host + " Found RF Frequency - 2 of 2!")
learned = ''.join(format(x, '02x') for x in bytearray(data))
_rf_sweep_message = "RF Scan Completed Successfully"
logger.info("Device:" + host + " RF Scan Completed Successfully")
time.sleep(1)
return JSONResponse('{"data":"' + learned + '"}')
return JSONResponse('{"data":"' + learned + '","type":"rf"}')

# Get RF Learning state

Expand Down Expand Up @@ -655,6 +659,28 @@ def get_device_status(request: Request, host: str = ""):
# endregion API Methods


@app.post("/api/code")
def create_code(code: Code):
return db.insert_code(code.CodeType, code.CodeName, code.Code)

@app.put("/api/code/{code_id}")
def update_code(code_id: int, code: Code):
return db.update_code(code_id, code.CodeType, code.CodeName, code.Code)

@app.delete("/api/code/{code_id}")
def delete_code(code_id: int):
return db.delete_code(code_id)

@app.get("/api/code/{code_id}")
def read_code(code_id: int):
return db.select_code(code_id)

@app.get("/api/codes")
def read_all_codes():
return db.select_all_codes(api_call=True)



# Start Application
if __name__ == '__main__':
logger.info("Broadlink Manager is up and running")
Expand Down
7 changes: 7 additions & 0 deletions broadlinkmanager/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from pydantic import BaseModel

class Code(BaseModel):
CodeId: int = None
CodeType: str
CodeName: str
Code: str
151 changes: 151 additions & 0 deletions broadlinkmanager/dist/js/codes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
$(document).ready(function () {
var table = $('#codesTable').DataTable();

// Load data into the table
$.ajax({
url: '/api/codes/', // Change this to your API endpoint
type: 'GET',
dataType: 'json',
success: function (data) {
data.forEach(function (item) {
table.row.add([
item.CodeName,
item.CodeType,
item.Code,
'<button class="edit">✏️</button><button class="save" style="display:none;">💾</button><button class="delete">❌</button>',
'<span style="display:none;">' + item.CodeId + '</span>'
]).draw(false);
});
},
error: function (xhr, status, error) {
Swal.fire({
toast: true,
position: 'top',
customClass: {
toast: 'swal2-toast-top'
},
icon: 'error',
title: 'Error loading data: ' + xhr.responseText,
showConfirmButton: false,
timer: 3000
});
}
});

// Handle edit button
$('#codesTable').on('click', '.edit', function () {
var row = $(this).closest('tr');
row.find('td:not(:last-child)').each(function (index) {
var cell = $(this);
if (index < 3) { // Skip the last cell (actions)
var content = cell.text();
cell.html('<input type="text" value="' + content + '">');
}
});
row.find('.edit').hide();
row.find('.save').show();
});

// Handle save button
$('#codesTable').on('click', '.save', function () {
var row = $(this).closest('tr');
var data = {
CodeId: row.find('td:eq(4) span').text(),
CodeName: row.find('td:eq(0) input').val(),
CodeType: row.find('td:eq(1) input').val(),
Code: row.find('td:eq(2) input').val()
};

$.ajax({
url: '/api/code/' + data.CodeId, // Change this to your API endpoint
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (response) {
row.find('td:not(:last-child)').each(function (index) {
var cell = $(this);
if (index < 3) { // Skip the last cell (actions)
var input = cell.find('input');
cell.text(input.val());
}
});
row.find('.edit').show();
row.find('.save').hide();
Swal.fire({
toast: true,
position: 'top',
customClass: {
toast: 'swal2-toast-top'
},
icon: 'success',
title: 'Code updated successfully',
showConfirmButton: false,
timer: 3000
});
},
error: function (xhr, status, error) {
Swal.fire({
toast: true,
position: 'top',
customClass: {
toast: 'swal2-toast-top'
},
icon: 'error',
title: 'Error updating code: ' + xhr.responseText,
showConfirmButton: false,
timer: 3000
});
}
});
});

// Handle delete button
$('#codesTable').on('click', '.delete', function () {
var row = $(this).closest('tr');
var codeId = row.find('td:eq(4) span').text();

Swal.fire({
title: 'Are you sure?',
text: 'You won\'t be able to revert this!',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: '/api/code/' + codeId, // Change this to your API endpoint
type: 'DELETE',
success: function (response) {
table.row(row).remove().draw(false);
Swal.fire({
toast: true,
position: 'top',
customClass: {
toast: 'swal2-toast-top'
},
icon: 'success',
title: 'Code deleted successfully',
showConfirmButton: false,
timer: 3000
});
},
error: function (xhr, status, error) {
Swal.fire({
toast: true,
position: 'top',
customClass: {
toast: 'swal2-toast-top'
},
icon: 'error',
title: 'Error deleting code: ' + xhr.responseText,
showConfirmButton: false,
timer: 3000
});
}
});
}
});
});
});
Loading

0 comments on commit d04e44a

Please sign in to comment.