mby functional system?

This commit is contained in:
Angoosh Leviocki 2025-04-09 23:18:11 +02:00
parent f230dc841e
commit fc8f89f412
Signed by: angoosh
GPG Key ID: 2DAE446D291BD8D3
6 changed files with 1254 additions and 0 deletions

View File

@ -0,0 +1,640 @@
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <SPIFFS.h>
#include <HardwareSerial.h>
HardwareSerial uart(0);
bool LoRa_Setup = false;
// WiFi credential
// Use different ssid for both module to avoid confusion
// example:
// const char* ssid = "ESP32-LoRa-Chat1"; for user 1
// const char* ssid = "ESP32-LoRa-Chat2"; for user 2
//const char* ssid = "ESP32-LoRa-Chat";
const char* password = "chatpass123";
WebServer server(80);
#define MAX_MESSAGES 50
String messageBuffer[MAX_MESSAGES];
int messageCount = 0;
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 LoRa Chat</title>
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--background-gradient-1: #667eea;
--background-gradient-2: #764ba2;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, var(--background-gradient-1), var(--background-gradient-2));
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px 0;
}
#username-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 10px;
text-align: center;
}
#username-input {
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 5px;
width: 200px;
}
#status-bar {
background: rgba(255, 255, 255, 0.1);
padding: 10px;
border-radius: 10px;
margin-bottom: 10px;
color: white;
font-size: 0.9em;
text-align: center;
width: 90%;
max-width: 400px;
}
#chat-container {
width: 90%;
max-width: 400px;
height: 65vh;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
overflow: hidden;
}
#message-area {
flex-grow: 1;
overflow-y: auto;
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
}
.message {
max-width: 80%;
padding: 10px 15px;
border-radius: 15px;
margin-bottom: 10px;
word-wrap: break-word;
}
.sent-message {
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
align-self: flex-end;
border-bottom-right-radius: 5px;
}
.received-message {
background: linear-gradient(135deg, #ecf0f1, #bdc3c7);
color: #2c3e50;
align-self: flex-start;
border-bottom-left-radius: 5px;
}
.username {
font-weight: bold;
font-size: 0.8em;
margin-bottom: 4px;
}
.message-info {
font-size: 0.7em;
opacity: 0.7;
margin-top: 4px;
}
.input-area {
display: flex;
padding: 15px;
background: rgba(255, 255, 255, 0.1);
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
#message-input {
flex-grow: 1;
padding: 10px 15px;
background: rgba(255, 255, 255, 0.2);
border: none;
border-radius: 30px;
margin-right: 10px;
color: white;
}
#message-input::placeholder {
color: rgba(255, 255, 255, 0.6);
}
button {
background: linear-gradient(135deg, #3498db, #2ecc71);
color: white;
border: none;
padding: 10px 20px;
border-radius: 30px;
cursor: pointer;
transition: transform 0.3s ease;
}
button:hover {
transform: scale(1.05);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
</head>
<body>
<div id="username-modal">
<div class="modal-content">
<h2>Enter your username</h2>
<input type="text" id="username-input" placeholder="Username">
<button id="username-submit">Join Chat</button>
</div>
</div>
<div id="status-bar">
Connecting...
</div>
<div id="chat-container">
<div id="message-area"></div>
<div class="input-area">
<input type="text" id="message-input" placeholder="Type a message..." disabled>
<button id="send-btn" disabled>Send</button>
</div>
</div>
<script>
const statusBar = document.getElementById('status-bar');
const messageArea = document.getElementById('message-area');
const messageInput = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
const usernameModal = document.getElementById('username-modal');
const usernameInput = document.getElementById('username-input');
const usernameSubmit = document.getElementById('username-submit');
let username = '';
let messageCheckInterval;
usernameSubmit.addEventListener('click', () => {
username = usernameInput.value.trim();
if (username) {
usernameModal.style.display = 'none';
initChat();
}
});
function initChat() {
statusBar.textContent = 'Connected';
statusBar.style.background = 'rgba(46, 204, 113, 0.2)';
messageInput.disabled = false;
sendBtn.disabled = false;
// Start checking for new messages
messageCheckInterval = setInterval(checkNewMessages, 1000);
}
function checkNewMessages() {
fetch('/messages')
.then(response => response.json())
.then(data => {
messageArea.innerHTML = ''; // Clear existing messages
data.messages.forEach(msg => {
const [sender, content] = msg.split(': ');
const type = sender === username ? 'sent' : 'received';
addMessage(content, type, sender);
});
})
.catch(error => {
console.error('Error fetching messages:', error);
statusBar.textContent = 'Connection error';
statusBar.style.background = 'rgba(231, 76, 60, 0.2)';
});
}
function addMessage(content, type, sender) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${type}-message`);
const usernameDiv = document.createElement('div');
usernameDiv.classList.add('username');
usernameDiv.textContent = sender;
messageDiv.appendChild(usernameDiv);
const messageContent = document.createElement('div');
messageContent.textContent = content;
messageDiv.appendChild(messageContent);
const messageInfo = document.createElement('div');
messageInfo.classList.add('message-info');
messageInfo.textContent = new Date().toLocaleTimeString();
messageDiv.appendChild(messageInfo);
messageArea.appendChild(messageDiv);
messageArea.scrollTop = messageArea.scrollHeight;
}
function sendMessage() {
const message = messageInput.value.trim();
if (message) {
fetch('/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: message,
sender: username
})
})
.then(response => response.json())
.then(data => {
if (data.status === 'sent') {
messageInput.value = '';
}
})
.catch(error => {
console.error('Error sending message:', error);
statusBar.textContent = 'Error sending message';
statusBar.style.background = 'rgba(231, 76, 60, 0.2)';
});
}
}
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
</script>
</body>
</html>
)rawliteral";
void LoRa_Join(){
uint32_t time = millis();
bool msg_done = true;
uart.println("AT+MODE=LWOTAA");
delay(1000);
while(1){
if(msg_done){
uart.println("AT+JOIN");
msg_done = false;
}
if(uart.available()){
String str = uart.readStringUntil('\n');
Serial.println(str);
if(strcmp(str.c_str(), "+JOIN: Join failed\r") == 0){
msg_done = true;
}
if(strcmp(str.c_str(), "+JOIN: Done\r") == 0){
if(!msg_done){
break;
}
}
}
}
}
void LoRa_Send_MSG(char* msg){
uart.println(msg);
while(1){
if(uart.available()){
String str = uart.readStringUntil('\n');
Serial.println(str);
if(strcmp(str.c_str(), "+MSG: Done\r") == 0){
break;
}
}
}
}
uint8_t lora_msg[32][51];
void LoRa_Send_MSGHEX(const char* msg, uint8_t port){//parses string into multiple messages if needed
//clear send buffer
for(int i = 0; i < 32; i++){
for(int j = 0; j < 51; j++){
lora_msg[i][j] = 0;
}
}
//get how many messages we will need (32 max = 1536 characters)
int len = strlen(msg);
int msg_no = len / 48;
if((len % 48) != 0){
msg_no ++;
}
//prepare messages
for(int i = 0; i < msg_no; i++){
if(len > 48){
lora_msg[i][0] = 51;
lora_msg[i][1] = i+1;
lora_msg[i][2] = msg_no;
for(int j = 0; j < 48; j++){
lora_msg[i][3+j] = msg[j+i*48];
}
len -= 48;
}
else{
lora_msg[i][0] = len+3;
lora_msg[i][1] = i+1;
lora_msg[i][2] = msg_no;
for(int j = 0; j < len; j++){
lora_msg[i][3+j] = msg[j+i*48];
}
len = 0;
}
}
//send messages
uart.printf("AT+PORT=%hhu\n", port);
delay(300);
for(int i = 0; i < 32; i++){
if(lora_msg[i][0] != 0){
uart.print("AT+MSGHEX=\"");
Serial.print("AT+MSGHEX=\"");
for(int j = 0; j < lora_msg[i][0]; j++){
uart.printf("%02X",lora_msg[i][j]);
Serial.printf("%02X",lora_msg[i][j]);
}
uart.println("\"");
Serial.println("\"");
}
else{
return;
}
while(1){
if(uart.available()){
String str = uart.readStringUntil('\n');
Serial.println(str);
if(strcmp(str.c_str(), "+MSGHEX: Done\r") == 0){
break;
}
}
}
}
}
int asciiToHex(char *asciiHexChar){
uint8_t hi, lo;
uint8_t x;
x = (asciiHexChar[0] & 0x4F);
hi = (x & 0x0F) + ((x >> 6) * 9);
x = (asciiHexChar[1] & 0x4F);
lo = (x & 0x0F) + ((x >> 6) * 9);
return (hi << 4) + lo;
}
int rx_buffer[32][51];
int rx_index = 0;
void LoRa_Receive_MSG(){
if(uart.available()){
String str = uart.readStringUntil('\n');
Serial.println(str);
if(str.indexOf("MSG: PORT: 1; RX:") > 0){
char rxBytes[3] = {0,0,0};
int rx_len = 51;
for(int i = 0; i < rx_len; i++){
for(int j = 0; j < 2; j++){
rxBytes[j] = str.c_str()[i*2+j+20];
}
rx_buffer[rx_index][i] = asciiToHex(rxBytes);
if(i == 0){
rx_len = rx_buffer[rx_index][0];
}
}
if(rx_buffer[rx_index][1] == rx_buffer[rx_index][2]){
//transmit whole message
rx_index = 0;
String rxString = "";
for(int i = 0; i < 32; i++){
for(int j = 3; j < (rx_buffer[i][0]); j++){
rxString += (char)rx_buffer[i][j];
}
if(rx_buffer[i][0] < 51){
break;
}
}
addMessageToBuffer(rxString);
}
}
}
}
void setup() {
Serial.begin(115200);
uart.begin(9600, SERIAL_8N1, RX, TX);
if(!SPIFFS.begin(true)) {
Serial.println("SPIFFS initialization failed!");
return;
}
Serial.println("Initializing LoRa...");
//add LoRa E5 module init here
pinMode(5, OUTPUT);
digitalWrite(5, LOW);
delay(1000);
digitalWrite(5, HIGH);
delay(2000);
if(!LoRa_Setup){
LoRa_Join();
char batt[1] = {20};
LoRa_Send_MSGHEX(batt, 7);
delay(1000);
uart.println("AT+CLASS=C");
//LoRa E5 module init done
char ssid[22];
sprintf(ssid, "ESP_Chat_%012llx", ESP.getEfuseMac());
WiFi.softAP(ssid, password);
Serial.println("Access Point Started");
Serial.print("IP Address: ");
Serial.println(WiFi.softAPIP());
server.on("/", HTTP_GET, handleRoot);
server.on("/send", HTTP_POST, handleSendMessage);
server.on("/messages", HTTP_GET, handleGetMessages);
server.begin();
Serial.println("Web Server Started");
}
Serial.println("Init DONE");
}
void handleRoot() {
server.send(200, "text/html", index_html);
}
void handleSendMessage() {
if (server.hasArg("plain")) {
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, server.arg("plain"));
if (!error) {
String message = doc["message"].as<String>();
String sender = doc["sender"].as<String>();
Serial.println("Sending message");
Serial.print("Sender: ");
Serial.println(sender);
Serial.print("Message: ");
Serial.println(message);
String lora_msg = sender + ": " + message;
LoRa_Send_MSGHEX(lora_msg.c_str(), 8);
addMessageToBuffer(sender + ": " + message);
server.send(200, "application/json", "{\"status\":\"sent\"}");
} else {
server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
}
}
}
void handleGetMessages() {
StaticJsonDocument<2048> doc;
JsonArray array = doc.createNestedArray("messages");
for(int i = 0; i < messageCount; i++) {
array.add(messageBuffer[i]);
}
String response;
serializeJson(doc, response);
server.send(200, "application/json", response);
}
void addMessageToBuffer(String message) {
if (messageCount >= MAX_MESSAGES) {
for(int i = 0; i < MAX_MESSAGES - 1; i++) {
messageBuffer[i] = messageBuffer[i + 1];
}
messageCount--;
}
messageBuffer[messageCount++] = message;
}
String incoming = "";
int incomingByte = 0;
void loop() {
if(!LoRa_Setup){
server.handleClient();
LoRa_Receive_MSG();
}
else{
if(Serial.available()){
String str = Serial.readStringUntil('\n');
Serial.println(str);
uart.println(str);
}
if(uart.available()){
String str = uart.readStringUntil('\n');
Serial.println(str);
}
}
//if(uart.available()){
// String str = uart.readStringUntil('\n');
// Serial.println(str);
// if(str.indexOf("MSG: PORT: 1; RX:") > 0){
// Serial.println("yayy");
// }
//}
//delay(1000);
//if(Serial.available()){
// String str = Serial.readStringUntil('\n');
// uart.println(str);
//}
/*
if (Serial.available() > 0) {
incomingByte = Serial.read();
if(incomingByte != '#'){
incoming += (char)incomingByte;
}
if(incomingByte == '#'){
addMessageToBuffer(incoming);
incoming = "";
}
}
*/
/*
int packetSize = LoRa.parsePacket();
if (packetSize) {
byte recipient = LoRa.read();
byte sender = LoRa.read();
String incoming = "";
while (LoRa.available()) {
incoming += (char)LoRa.read();
}
if (recipient == localAddress) {
addMessageToBuffer(incoming);
}
}*/
}

View File

@ -0,0 +1,23 @@
{
"device": "test",
"devEui": "2cf7f1203230a02e",
"app": "comms",
"appId": "d60506c4-09de-4ca1-b147-f13be7b90380",
"rx_metadata": [
{
"gateway": "353036202b000e00",
"time": "2025-04-09T16:19:55.924657+00:00",
"rssi": -38,
"snr": 10.25
}
],
"frame_port": 8,
"frame_count": 3,
"data": "EAEBYW5nb29zaDogdGVzdA==",
"payload": {
"msgprts": 1.0,
"len": 16.0,
"message": "angoosh: test",
"msgno": 1.0
}
}

View File

@ -0,0 +1,20 @@
{
"device": "test",
"app": "comms",
"rx_metadata": [
{
"gateway": "353036202b000e00",
"time": "2025-04-09T15:31:03.252565+00:00",
"rssi": -41,
"snr": 9.25
}
],
"frame_port": 8,
"frame_count": 11,
"payload": {
"message": "th of multiple messages for forward processing",
"len": 49.0,
"msgno": 2.0,
"msgprts": 2.0
}
}

145
Comms/logs/app.log Normal file
View File

@ -0,0 +1,145 @@
[2025-04-05 10:53:00.980581] MQTT Subscribtion started
[2025-04-05 10:53:00.980590] Time: 2025-04-05 10:53:00.980596
[2025-04-05 10:53:00.980603] Server: 10.0.69.69
[2025-04-05 10:53:00.980609] appId:
[2025-04-05 10:53:00.980615] psw:
[2025-04-05 10:54:08.025691] disconnect
[2025-04-05 10:54:53.086109] MQTT Subscribtion started
[2025-04-05 10:54:53.086116] Time: 2025-04-05 10:54:53.086119
[2025-04-05 10:54:53.086122] Server: 10.0.69.69
[2025-04-05 10:54:53.086125] appId:
[2025-04-05 10:54:53.086128] psw:
[2025-04-05 10:57:35.874296] disconnect
[2025-04-09 17:23:37.501367] MQTT Subscribtion started
[2025-04-09 17:23:37.501374] Time: 2025-04-09 17:23:37.501377
[2025-04-09 17:23:37.501380] Server: 10.0.69.69
[2025-04-09 17:23:37.501384] appId:
[2025-04-09 17:23:37.501387] psw:
[2025-04-09 17:24:38.121184] disconnect
[2025-04-09 17:24:40.002282] MQTT Subscribtion started
[2025-04-09 17:24:40.002297] Time: 2025-04-09 17:24:40.002305
[2025-04-09 17:24:40.002313] Server: 10.0.69.69
[2025-04-09 17:24:40.002323] appId:
[2025-04-09 17:24:40.002330] psw:
[2025-04-09 17:25:53.568712] disconnect
[2025-04-09 17:25:54.845438] MQTT Subscribtion started
[2025-04-09 17:25:54.845445] Time: 2025-04-09 17:25:54.845448
[2025-04-09 17:25:54.845451] Server: 10.0.69.69
[2025-04-09 17:25:54.845454] appId:
[2025-04-09 17:25:54.845457] psw:
[2025-04-09 17:26:41.579455] disconnect
[2025-04-09 17:26:42.390092] MQTT Subscribtion started
[2025-04-09 17:26:42.390098] Time: 2025-04-09 17:26:42.390101
[2025-04-09 17:26:42.390104] Server: 10.0.69.69
[2025-04-09 17:26:42.390107] appId:
[2025-04-09 17:26:42.390110] psw:
[2025-04-09 17:27:34.512989] MQTT Subscribtion started
[2025-04-09 17:27:34.512995] Time: 2025-04-09 17:27:34.512997
[2025-04-09 17:27:34.513000] Server: 10.0.69.69
[2025-04-09 17:27:34.513004] appId:
[2025-04-09 17:27:34.513006] psw:
[2025-04-09 17:28:27.480157] MQTT Subscribtion started
[2025-04-09 17:28:27.480164] Time: 2025-04-09 17:28:27.480167
[2025-04-09 17:28:27.480170] Server: 10.0.69.69
[2025-04-09 17:28:27.480173] appId:
[2025-04-09 17:28:27.480176] psw:
[2025-04-09 17:29:35.171782] MQTT Subscribtion started
[2025-04-09 17:29:35.171789] Time: 2025-04-09 17:29:35.171792
[2025-04-09 17:29:35.171795] Server: 10.0.69.69
[2025-04-09 17:29:35.171798] appId:
[2025-04-09 17:29:35.171801] psw:
[2025-04-09 17:30:19.792010] MQTT Subscribtion started
[2025-04-09 17:30:19.792019] Time: 2025-04-09 17:30:19.792022
[2025-04-09 17:30:19.792025] Server: 10.0.69.69
[2025-04-09 17:30:19.792029] appId:
[2025-04-09 17:30:19.792032] psw:
[2025-04-09 17:53:18.410457] MQTT Subscribtion started
[2025-04-09 17:53:18.410463] Time: 2025-04-09 17:53:18.410466
[2025-04-09 17:53:18.410470] Server: 10.0.69.69
[2025-04-09 17:53:18.410473] appId:
[2025-04-09 17:53:18.410476] psw:
[2025-04-09 17:54:49.122914] disconnect
[2025-04-09 17:54:50.284824] MQTT Subscribtion started
[2025-04-09 17:54:50.284833] Time: 2025-04-09 17:54:50.284838
[2025-04-09 17:54:50.284843] Server: 10.0.69.69
[2025-04-09 17:54:50.284849] appId:
[2025-04-09 17:54:50.284855] psw:
[2025-04-09 17:56:02.531867] disconnect
[2025-04-09 17:56:03.462168] MQTT Subscribtion started
[2025-04-09 17:56:03.462176] Time: 2025-04-09 17:56:03.462181
[2025-04-09 17:56:03.462187] Server: 10.0.69.69
[2025-04-09 17:56:03.462193] appId:
[2025-04-09 17:56:03.462199] psw:
[2025-04-09 18:00:06.088614] disconnect
[2025-04-09 18:00:07.107735] MQTT Subscribtion started
[2025-04-09 18:00:07.107742] Time: 2025-04-09 18:00:07.107745
[2025-04-09 18:00:07.107748] Server: 10.0.69.69
[2025-04-09 18:00:07.107751] appId:
[2025-04-09 18:00:07.107754] psw:
[2025-04-09 18:04:00.060780] MQTT Subscribtion started
[2025-04-09 18:04:00.060789] Time: 2025-04-09 18:04:00.060794
[2025-04-09 18:04:00.060799] Server: 10.0.69.69
[2025-04-09 18:04:00.060805] appId:
[2025-04-09 18:04:00.060810] psw:
[2025-04-09 18:05:45.152635] disconnect
[2025-04-09 18:05:46.662378] MQTT Subscribtion started
[2025-04-09 18:05:46.662385] Time: 2025-04-09 18:05:46.662388
[2025-04-09 18:05:46.662391] Server: 10.0.69.69
[2025-04-09 18:05:46.662394] appId:
[2025-04-09 18:05:46.662397] psw:
[2025-04-09 18:07:01.511033] disconnect
[2025-04-09 18:07:02.767217] MQTT Subscribtion started
[2025-04-09 18:07:02.767224] Time: 2025-04-09 18:07:02.767227
[2025-04-09 18:07:02.767230] Server: 10.0.69.69
[2025-04-09 18:07:02.767233] appId:
[2025-04-09 18:07:02.767236] psw:
[2025-04-09 18:07:28.701363] disconnect
[2025-04-09 18:09:25.011915] MQTT Subscribtion started
[2025-04-09 18:09:25.011923] Time: 2025-04-09 18:09:25.011926
[2025-04-09 18:09:25.011930] Server: 10.0.69.69
[2025-04-09 18:09:25.011933] appId:
[2025-04-09 18:09:25.011936] psw:
[2025-04-09 18:13:26.440723] disconnect
[2025-04-09 18:19:50.218010] MQTT Subscribtion started
[2025-04-09 18:19:50.218016] Time: 2025-04-09 18:19:50.218020
[2025-04-09 18:19:50.218023] Server: 10.0.69.69
[2025-04-09 18:19:50.218026] appId:
[2025-04-09 18:19:50.218029] psw:

416
Comms/main.py Executable file
View File

@ -0,0 +1,416 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 28 19:30:56 2022
@author: angoosh
"""
import paho.mqtt.client as mqtt #knihovna pro prijem mqtt packetu
import paho.mqtt.publish as publish
import json #knihovna pro praci s json formatem
import datetime #knihovna pro nacteni casu
import os, os.path #os knihovna
import errno #knihovna pro chyby
import sys #knihovna pro praci s interpretrem
import psycopg2 #knihovna pro praci s postgresql databazi
import re #regex
#nacti aktualni pracovni slozku
WORKDIR = os.getcwd()
DEVICES=["2cf7f1203230a02e"]
#MQTT port
PORT = 1884
APPID = ""
PSW = ""
#promenne pro jednotlive moznosti zapisu
write_json = 0
write_db = 0
keep_last = 0;
#nacteni argumentu
arguments = sys.argv
argument_index = 0;
#kam se maji ukladat jednotliva csv a json data a logy
JSON_PATH = WORKDIR+'/data/json/'
LOG_PATH = WORKDIR+'/logs/'
#funkce pro povoleni zapisu dat do json
def enableJson():
global write_json
write_json = 1
return 0
#funkce pro povoleni zapisu dat do databaze
def enableDB():
global write_db
write_db = 1
return 0
#funkce pro vypnuti historie json souboru
def discardOldJsonData():
global keep_last
keep_last = 1
return 0
#funkce pro nacteni prihlasovacich udaju a dalsich metadat ze souboru
def jsonLogin(index):
global APPEUI, APPID, PSW, DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_TABLE
loaded_json = ''
login_json = arguments[index + 1]
with open(login_json, 'r') as file:
for line in file:
loaded_json += line
login_creds = json.loads(loaded_json)
APPEUI = login_creds['appeui']
APPID = login_creds['appid']
PSW = login_creds['psw']
try:
DB_HOST = login_creds['DB_HOST']
DB_NAME = login_creds['DB_NAME']
DB_USER = login_creds['DB_USER']
DB_PASS = login_creds['DB_PASS']
DB_TABLE = login_creds['DB_TABLE']
except:
pass
return 1
#nastav APPID
def setAppId(index):
global APPID
APPID = arguments[index + 1]
return 1
#nastav APPEUI
def setAppEui(index):
global APPEUI
APPEUI = arguments[index + 1]
return 1
#nastav APPKEY
def setPsw(index):
global PSW
PSW = arguments[index + 1]
return 1
#nastav adresu databazoveho serveru
def set_dbHost(index):
global DB_HOST
DB_HOST = arguments[index + 1]
return 1
#nastav jmeno databaze
def set_dbName(index):
global DB_NAME
DB_NAME = arguments[index + 1]
return 1
#nastav uzivatele databaze
def set_dbUser(index):
global DB_USER
DB_USER = arguments[index + 1]
return 1
#nastav heslo pro databazoveho uzivatele
def set_dbPass(index):
global DB_PASS
DB_PASS = arguments[index + 1]
return 1
#zobraz help pro vsecky argumenty
def appHelp():
print('mqtt_sub.py [OPTIONS]')
print(' -j Save messages to json, json per message')
print(' -do Discard old jsons, also json is not saved with time in name')
print(' -db Save data to postgres database')
print(' -dbhost Database hostmane')
print(' -dbname Database name')
print(' -dbuser Database user')
print(' -dbpass Database password')
print(' -l [FILE] Load login data from specified')
print(' -s [SERVER] MQTT server address')
print(' -a [ID] Id of application on server')
print(' -p [PASS] API key for mqtt')
print(' -h print this help message')
exit()
#zkontroluj, zda souborova cesta existuje
def checkPath(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
#konverze bajtu na cislo
def bytes_to_decimal(i,d):
xx = i - 127
dec = (-d if xx < 0 else d)/100
return xx + dec
#co se ma provest pri pripojeni na mqtt server
def on_connect(client, userdata, flags, rc):
client.subscribe('application/+/device/+/event/up')
#co se ma stat, kdyz prijme mqtt packet
def on_message(client, userdata, msg):
#nacteni zpravy
j_msg = json.loads(msg.payload.decode('utf-8'))
#nacteni identifikace zarizeni, ze ktereho zprava prisla
app_name = j_msg['deviceInfo']['applicationName']
dev_name = j_msg['deviceInfo']['deviceName']
app_id = j_msg['deviceInfo']['applicationId']
dev_eui = j_msg['deviceInfo']['devEui']
msg_b64_data = j_msg['data']
if app_name != "comms":
return
#nacteni metadat zpravy
rx_metadata_in = j_msg['rxInfo']
rx_metadata = []
for gateway in range(len(rx_metadata_in)):
rx_metadata.append({})
try:
rx_metadata[gateway]['gateway'] = rx_metadata_in[gateway]['gatewayId']
except:
rx_metadata[gateway]['gateway'] = 'Unknown'
try:
rx_metadata[gateway]['time'] = rx_metadata_in[gateway]['gwTime']
except:
rx_metadata[gateway]['time'] = 'Unknown'
try:
rx_metadata[gateway]['rssi'] = rx_metadata_in[gateway]['rssi']
except:
rx_metadata[gateway]['rssi'] = 'Unknown'
try:
rx_metadata[gateway]['snr'] = rx_metadata_in[gateway]['snr']
except:
rx_metadata[gateway]['snr'] = 'Unknown'
try:
frame_port = j_msg['fPort']
frame_count = j_msg['fCnt']
except:
frame_port = 0;
frame_count = 0;
#nacteni obsahu zpravy
decoded_payload_dict = j_msg['object']
#priprava pro json, co se ulozi
message_dict = {
'device': dev_name,
'devEui': dev_eui,
'app': app_name,
'appId': app_id,
'rx_metadata': rx_metadata,
'frame_port': frame_port,
'frame_count': frame_count,
'data': msg_b64_data,
'payload': decoded_payload_dict
}
#print(message_dict)
#ulozeni zpravy pro preposlani do json
json_out = json.dumps(message_dict, indent = 4)
with open('ZKJ_tmp_message_'+str(int(decoded_payload_dict["msgno"]))+'.json','w') as file:
file.write(json_out)
if decoded_payload_dict["msgno"] == decoded_payload_dict["msgprts"]:
for i in range(1,33):
try:
with open('ZKJ_tmp_message_'+str(i)+'.json','r') as file:
loaded_json = ''
for line in file:
loaded_json += line
msg = json.loads(loaded_json)
#print(msg)
downlink = {
'devEui': msg['devEui'],
'confirmed': False,
'fPort': 1,
'data': msg['data']
}
try:
for device in DEVICES:
lst = list(downlink['data'])
lst[7] = 'f'
downlink['data'] = ''.join(lst)
ttn_client.publish("application/"+msg['appId']+"/device/"+device+"/command/down", json.dumps(downlink, indent = 4))
except Exception as e: print(e)
except:
pass
#ulozeni dat do json
if write_json == 1:
json_out = json.dumps(message_dict, indent = 4)
checkPath(JSON_PATH)
if keep_last == 1:
with open(JSON_PATH+'ZKJ_Comms_'+dev_id+'.json','w') as file:
file.write(json_out)
else:
with open(JSON_PATH+'ZKJ_Comms_'+dev_id+'_'+str(datetime.datetime.now())+'.json','w') as file:
file.write(json_out)
#ulozeni dat do databaze
if write_db == 1:
#orezani jmena zarizeni na pouze modelovy nazev
with open(LOG_PATH+'app.log','a') as log:
log.write("dev_name: "+dev_name+"\n")
#datovy string co se ma ulozit do databaze
db_string = dev_name+","+decoded_payload_dict['message']
#header sloupccu databazove tabulky, pouzije se pouze, kdyz tabulka nebude existovat
db_columns = "Id SERIAL PRIMARY KEY, "+\
"DevName VARCHAR(100), "+\
"Message VARCHAR(100), "+\
"created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP"
#header sloupcu do kterych se ma zapsat db_string. db_string a db_col_wrt musi mit stejne poradi headeru a dat
db_col_wrt = "DevName,"+\
"Message"
#pripojeni na databazi, kontrola zda tabulka existuje a nasledne zapsani dat
con = psycopg2.connect("host="+DB_HOST+" dbname="+DB_NAME+" user="+DB_USER+" password="+DB_PASS)
cur = con.cursor()
cur.execute("SELECT EXISTS ( SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = \'"+DB_TABLE+"\');")
if not cur.fetchone()[0]:
try:
cur.execute("CREATE TABLE "+DB_TABLE+"("+db_columns+")")
cur.execute("INSERT INTO "+DB_TABLE+"("+db_col_wrt+") VALUES("+db_string+")")
con.commit()
except (psycopg2.DatabaseError):
if con:
con.rollback()
sys.exit(1)
finally:
if con:
con.close()
else:
try:
cur.execute("INSERT INTO "+DB_TABLE+"("+db_col_wrt+") VALUES("+db_string+")")
con.commit()
except (psycopg2.DatabaseError):
if con:
con.rollback()
sys.exit(1)
finally:
if con:
con.close()
print("Starting app")
#kontrola, zda application log soubor existuje
checkPath(LOG_PATH)
try:
with open(LOG_PATH+"app.log","a") as log:
pass
except:
with open(LOG_PATH+"app.log","w") as log:
log.write('LOG_START\n')
#proskenovani jednotlivych argumentu
for arg in range(1, len(sys.argv)):
if arguments[arg] == '-j':
arg += enableJson()
elif arguments[arg] == '-do':
arg += discardOldJsonData()
elif arguments[arg] == '-l':
arg += jsonLogin(arg)
elif arguments[arg] == '-a':
arg += setAppId(arg)
elif arguments[arg] == '-s':
arg += setAppEui(arg)
elif arguments[arg] == '-p':
arg += setPsw(arg)
elif arguments[arg] == '-h':
appHelp()
elif arguments[arg] == '-db':
arg += enableDB()
elif arguments[arg] == '-dbhost':
arg += set_dbHost(arg)
elif arguments[arg] == '-dbname':
arg += set_dbName(arg)
elif arguments[arg] == '-dbuser':
arg += set_dbUser(arg)
elif arguments[arg] == '-dbpass':
arg += set_dbPass(arg)
else:
pass
#Init message
print('MQTT Subscribtion started')
print('Time: ', str(datetime.datetime.now()))
print('Server: ', APPEUI)
print('appId: ', APPID)
print('psw: ', PSW)
print('')
with open(LOG_PATH+'app.log','a') as log:
log.write("\n\n["+str(datetime.datetime.now())+"] MQTT Subscribtion started\n")
log.write("["+str(datetime.datetime.now())+"] Time: "+str(datetime.datetime.now())+"\n")
log.write("["+str(datetime.datetime.now())+"] Server: "+APPEUI+"\n")
log.write("["+str(datetime.datetime.now())+"] appId: "+APPID+"\n")
log.write("["+str(datetime.datetime.now())+"] psw: "+PSW+"\n")
if write_json == 1:
print('Saving data to json')
if keep_last == 0:
print('Keeping only the newest json')
else:
print('Keeping all jsons')
print('Json path: '+JSON_PATH)
print('')
with open(LOG_PATH+'app.log','a') as log:
log.write("["+str(datetime.datetime.now())+"] Saving data to json\n")
if keep_last == 0:
log.write("["+str(datetime.datetime.now())+"] Keeping only the newest json\n")
else:
log.write("["+str(datetime.datetime.now())+"] Keeping all jsons\n")
log.write("["+str(datetime.datetime.now())+"] Json path: "+JSON_PATH+"\n")
if write_db == 1:
print('Saving data to postgreSQL database')
print('Server: ', DB_HOST)
print('Database: ', DB_NAME)
print('User: ', DB_USER)
print('Password: ', DB_PASS)
print('')
with open(LOG_PATH+'app.log','a') as log:
log.write("["+str(datetime.datetime.now())+"] Saving data to postgreSQL database\n")
log.write("["+str(datetime.datetime.now())+"] Server: "+DB_HOST+"\n")
log.write("["+str(datetime.datetime.now())+"] Database: "+DB_NAME+"\n")
log.write("["+str(datetime.datetime.now())+"] User: "+DB_USER+"\n")
log.write("["+str(datetime.datetime.now())+"] Password: "+DB_PASS+"\n")
# set paho.mqtt callback
ttn_client = mqtt.Client()
ttn_client.on_connect = on_connect
ttn_client.on_message = on_message
ttn_client.username_pw_set(APPID, PSW)
ttn_client.connect(APPEUI, PORT, 60) #MQTT port over TLS
try:
ttn_client.loop_forever()
except KeyboardInterrupt:
print('disconnect')
with open(LOG_PATH+'app.log','a') as log:
log.write("["+str(datetime.datetime.now())+"] disconnect\n")
ttn_client.disconnect()

10
Comms/zkj.json Normal file
View File

@ -0,0 +1,10 @@
{
"appeui": "10.0.69.69",
"appid": "",
"psw": "",
"DB_HOST": "localhost",
"DB_NAME": "dedbeef",
"DB_USER": "python-test",
"DB_PASS": "password",
"DB_TABLE": "messages"
}