diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b810e31
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=lf
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3bc6878
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/
+/LoxBerry-Plugin-P1-Decrypter.iml
diff --git a/README-german.md b/README-german.md
new file mode 100644
index 0000000..ed89590
--- /dev/null
+++ b/README-german.md
@@ -0,0 +1,80 @@
+# Loxberry Plugin: P1 Decrypter
+
+Dieses Plugin ermöglicht es verschlüsselte Daten von einem Smart Meter über die Kundenschnittstelle P1 an den Miniserver über UDP und/oder an einen seriellen Port am Loxberry zu senden.
+
+> English readme: [https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/blob/main/README.md](https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/blob/main/README.md)
+
+
+
+## Voraussetzung
+
+- Smart Meter mit P1 Schnittstelle (Aktuell wurde das Plugin getestet mit dem Smart Meter: Sagemcom T210-D-r in Österreich)
+- FTDI USB Kabel zum verbinden des Smart Meter mit Loxberry.
+ - Zum Beispiel: [https://www.aliexpress.com/item/32945225256.html](https://www.aliexpress.com/item/32945225256.html)
+- Der Netzbetreiber muss die Kundenschnittstelle aktivieren und einen Key _"Global Unicast Encryption Key (GUEK)"_ zur Verfügung stellen
+ - Normalerweise kann über die Weboberfläche des Netzbetreibers die Kundenschnittstelle aktiviert und der Key angezeigt werden
+ - Das Aktivieren über die Weboberfläche des Netzbetreibers kann etwas Zeit in Anspruch nehmen
+
+## Smart Meter
+
+### T210-D-r (Österreich)
+
+
+
+| OBIS-Code | Einheit | Beschreibung |
+|-----------|--------------|---------------------------------------------------------|
+| 1-3:0.2.8 | int | P1 port DSMR version |
+| 0-0:1.0.0 | YYMMDDhhmmss | Impuls Datum und Zeit |
+| 1-0:1.8.0 | Wh | Zählerstand +P (Wirkenergie Bezug) |
+| 1-0:1.8.1 | Wh | Active energy import (+A) rate 1 |
+| 1-0:1.8.2 | Wh | Active energy import (+A) rate 2 |
+| 1-0:1.7.0 | W | aktuelle Leistung +P (momentane Wirkleistung Bezug) |
+| 1-0:2.8.0 | Wh | Zählerstand -P (Wirkenergie Lieferung) |
+| 1-0:2.8.1 | Wh | Active energy export (-A) rate 1 |
+| 1-0:2.8.2 | Wh | Active energy export (-A) rate 2 |
+| 1-0:2.7.0 | W | Aktuelle Leistung -P (momentane Wirkleistung Lieferung) |
+| 1-0:3.8.0 | varh | Blindenergie +R (Blindenergie Bezug) |
+| 1-0:3.8.1 | varh | Reactive energy import (+R) rate 1 |
+| 1-0:3.8.2 | varh | Reactive energy import (+R) rate 2 |
+| 1-0:3.7.0 | var | Momentanleistung +Q (var) |
+| 1-0:4.8.0 | varh | Blindenergie Lieferung -R (Wh) |
+| 1-0:4.8.1 | varh | Reactive energy export (-R) rate 1 |
+| 1-0:4.8.2 | varh | Reactive energy export (-R) rate 2 |
+| 1-0:4.7.0 | var | Momentanleistung -Q (var) |
+
+## Value mapping
+
+Das value mapping reduziert die information welche vom Smart Meter kommen.
+
+Format ist:
+```
+'label','regex'
+'label','regex'
+'label','regex'
+...
+```
+> Das value mapping kann mittels `raw` switch deaktiviert werden.
+
+### Beispiel
+
+Um folgenden Wert `1-0:1.8.0:001234567` vom Original output `1-0:1.8.0(001234567*Wh)` zu erhalten
+kann das value mapping wie folgt aussehen: `'1-0:1.8.0','(?<=1-0:1.8.0\().*?(?=\*Wh)'`
+
+## Miniserver Konfiguration
+
+- Virtueller UPD Eingang:
+ - Senderadresse: Deine Loxberry IP
+ - UPD Empfangsport: 54321 (Bzw. welcher im Plugin konfiguiert wurde)
+- Virtueller UPD Einfang Befehl:
+ - Befehlserkennung (Wenn die Daten wie im Value Mapping Beispiel geschickt werden): `\i1-0:1.8.0:\i\v`
+
+### Beispiel für den Energiemonitor
+
+- Die Werte kommen im Beispiel in Watt und müssen noch in Kilowatt umgerechnet werden `AI1/1000`
+- Im Beispiel muss der Wert `1-0:1.7.0` und `1-0:2.7.0` mit folgender Formel verbunden werden `(I1-I2)/1000`
+
+
+
+## Danke an:
+
+- tknaller - Für seinen modifizierten fork: https://github.com/tknaller/smarty_dsmr_proxy
\ No newline at end of file
diff --git a/README.md b/README.md
index 0895891..f7d92fe 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,77 @@
-# LoxBerry-Plugin-P1-Decrypter
\ No newline at end of file
+# Loxberry Plugin: P1 Decrypter
+
+Plugin to decrypt Smart Meter output over P1 customer interface and send it over udp and/or to a serial port.
+
+> German readme: [https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/blob/main/README-german.md](https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/blob/main/README-german.md)
+
+
+
+## Precondition
+
+- Smart Meter that has a P1 interface (Tested with Smart Meter: Sagemcom T210-D-r in Austria)
+- FTDI USB cable to connect to the Smart Meter
+ - One possibly option: [https://www.aliexpress.com/item/32945225256.html](https://www.aliexpress.com/item/32945225256.html)
+- Your energy provider has to activate your customer interface and provide the encryption key _"Global Unicast Encryption Key (GUEK)"_
+
+## Smart Meter
+
+### T210-D-r (Austria)
+
+
+
+| OBIS-Code | Einheit | Beschreibung |
+|-----------|--------------|---------------------------------------------------------|
+| 1-3:0.2.8 | int | P1 port DSMR version |
+| 0-0:1.0.0 | YYMMDDhhmmss | Impuls Datum und Zeit |
+| 1-0:1.8.0 | Wh | Zählerstand +P (Wirkenergie Bezug) |
+| 1-0:1.8.1 | Wh | Active energy import (+A) rate 1 |
+| 1-0:1.8.2 | Wh | Active energy import (+A) rate 2 |
+| 1-0:1.7.0 | W | aktuelle Leistung +P (momentane Wirkleistung Bezug) |
+| 1-0:2.8.0 | Wh | Zählerstand -P (Wirkenergie Lieferung) |
+| 1-0:2.8.1 | Wh | Active energy export (-A) rate 1 |
+| 1-0:2.8.2 | Wh | Active energy export (-A) rate 2 |
+| 1-0:2.7.0 | W | Aktuelle Leistung -P (momentane Wirkleistung Lieferung) |
+| 1-0:3.8.0 | varh | Blindenergie +R (Blindenergie Bezug) |
+| 1-0:3.8.1 | varh | Reactive energy import (+R) rate 1 |
+| 1-0:3.8.2 | varh | Reactive energy import (+R) rate 2 |
+| 1-0:3.7.0 | var | Momentanleistung +Q (var) |
+| 1-0:4.8.0 | varh | Blindenergie Lieferung -R (Wh) |
+| 1-0:4.8.1 | varh | Reactive energy export (-R) rate 1 |
+| 1-0:4.8.2 | varh | Reactive energy export (-R) rate 2 |
+| 1-0:4.7.0 | var | Momentanleistung -Q (var) |
+
+## Value mapping
+
+If you don't need all informations of your smart meter you can use the value mapping.
+Format is:
+```
+'label','regex'
+'label','regex'
+'label','regex'
+...
+```
+
+> Disable value mapping by enable `raw` switch.
+
+### Example
+
+To get `1-0:1.8.0:001234567\n` from raw output `1-0:1.8.0(001234567*Wh)`use value mapping like this: `'1-0:1.8.0','(?<=1-0:1.8.0\().*?(?=\*Wh)'`
+
+## Miniserver configuration
+
+- Virtual UPD input:
+ - IP address: Your Loxberry IP
+ - UPD Port: 54321 (or what you use configured over the plugin configuration)
+- Virtual UPD input command:
+ - command recognition (If you use the value mapping example above): `\i1-0:1.8.0:\i\v`
+
+### Example to use by energy monitor
+
+- In this example all values are in Watt. They have to be divide `AI1/1000`
+- In this example `1-0:1.7.0` and `1-0:2.7.0` must be connected by this formula `(I1-I2)/1000`
+
+
+
+## Thanks to:
+
+- tknaller - For his modified fork: https://github.com/tknaller/smarty_dsmr_proxy
\ No newline at end of file
diff --git a/bin/p1decrypter.py b/bin/p1decrypter.py
new file mode 100644
index 0000000..b363552
--- /dev/null
+++ b/bin/p1decrypter.py
@@ -0,0 +1,350 @@
+import socket
+import serial
+import binascii
+import argparse
+import re
+import logging
+import sys
+import os
+import configparser
+import json
+import base64
+from Cryptodome.Cipher import AES
+
+
+class P1decrypter:
+ def __init__(self):
+
+ self.STATE_IGNORING = 0
+ self.STATE_STARTED = 1
+ self.STATE_HAS_SYSTEM_TITLE_LENGTH = 2
+ self.STATE_HAS_SYSTEM_TITLE = 3
+ self.STATE_HAS_SYSTEM_TITLE_SUFFIX = 4
+ self.STATE_HAS_DATA_LENGTH = 5
+ self.STATE_HAS_SEPARATOR = 6
+ self.STATE_HAS_FRAME_COUNTER = 7
+ self.STATE_HAS_PAYLOAD = 8
+ self.STATE_HAS_GCM_TAG = 9
+ self.STATE_DONE = 10
+
+ # Command line arguments
+ self._args = {}
+
+ # Serial connection to p1 smart meter interface
+ self._connection = None
+
+ # Initial empty values. These will be filled as content is read
+ # and they will be reset each time we go back to the initial state.
+ self._state = self.STATE_IGNORING
+ self._buffer = ""
+ self._buffer_length = 0
+ self._next_state = 0
+ self._system_title_length = 0
+ self._system_title = b""
+ self._data_length_bytes = b"" # length of "remaining data" in bytes
+ self._data_length = 0 # length of "remaining data" as an integer
+ self._frame_counter = b""
+ self._payload = b""
+ self._gcm_tag = b""
+
+ self.LBSCONFIG = ""
+ self.miniserver_id = ""
+ self.general_json = {}
+
+ def main(self):
+ self.args()
+
+ def args(self):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('key', help="Global Unicast Encryption Key (GUEK)")
+
+ parser.add_argument('-iport', '--serial-input-port', required=False, default="/dev/ttyUSB0",
+ help="Serial input port. Default: /dev/ttyUSB0")
+ parser.add_argument('-ibaudrate', '--serial-input-baudrate', required=False, type=int, default=115200,
+ help="Serial input baudrate. Default: 115200")
+ parser.add_argument('-iparity', '--serial-input-parity', required=False, default=serial.PARITY_NONE,
+ help="Serial input parity. Default: None")
+ parser.add_argument('-istopbits', '--serial-input-stopbits', required=False, type=int,
+ default=serial.STOPBITS_ONE,
+ help="Serial input stopbits. Default: 1")
+
+ parser.add_argument('-m', '--mapping', required=False,
+ default="'1-0:1.8.0','(?<=1-0:1.8.0\().*?(?=\*Wh)'\n'1-0:1.7.0','(?<=1-0:1.7.0\().*?(?=\*W)'\n'1-0:2.8.0','(?<=1-0:2.8.0\().*?(?=\*Wh)'\n'1-0:2.7.0','(?<=1-0:2.7.0\().*?(?=\*W)'",
+ help="Value mapping. Default: '1-0:1.8.0','(?<=1-0:1.8.0\().*?(?=\*Wh)',\\n'1-0:1.7.0','(?<=1-0:1.7.0\().*?(?=\*W)'\\n'1-0:2.8.0','(?<=1-0:2.8.0\().*?(?=\*Wh)'\\n'1-0:2.7.0','(?<=1-0:2.7.0\().*?(?=\*W)'")
+
+ parser.add_argument('-a', '--aad', required=False, default="3000112233445566778899AABBCCDDEEFF",
+ help="Additional authenticated data. Default: 3000112233445566778899AABBCCDDEEFF")
+
+ parser.add_argument('-u', '--send-to-udp', required=False, default=True, action='store_true',
+ help="Send data to UDP. Default: true")
+ parser.add_argument('-ui', '--udp-host', help="UDP IP / Host")
+ parser.add_argument('-up', '--udp-port', type=int, help="UDP port")
+
+ parser.add_argument('-s', '--send-to-serial-port', required=False, default=False, action='store_true',
+ help="Send data to output serial port. Use socat to generate virtual port e.g.: socat -d -d pty,raw,echo=0,link=/dev/p1decrypterI pty,raw,echo=0,link=/dev/p1decrypterO")
+ parser.add_argument('-oport', '--serial-output-port', required=False, default="/dev/t210dr",
+ help="Serial output port. Default: /dev/p1decrypter")
+ parser.add_argument('-obaudrate', '--serial-output-baudrate', required=False, type=int, default=115200,
+ help="Serial output baudrate. Default: 115200")
+ parser.add_argument('-oparity', '--serial-output-parity', required=False, default=serial.PARITY_NONE,
+ help="Serial output parity. Default: None")
+ parser.add_argument('-ostopbits', '--serial-output-stopbits', required=False, type=int,
+ default=serial.STOPBITS_ONE,
+ help="Serial output stopbits. Default: 1")
+
+ parser.add_argument('-r', '--raw', required=False, default=False, action='store_true',
+ help="Output raw, without mapping")
+ parser.add_argument('-v', "--verbose", required=False, default=False, action='store_true', help="Verbose mode")
+ parser.add_argument('-l', '--logfile', required=False, help="Logfile path")
+ parser.add_argument('-c', "--configfile", required=False, help="Configfile path")
+
+ self._args = parser.parse_args()
+
+ self.config()
+
+ def config(self):
+
+ if self._args.logfile:
+ logging.basicConfig(filename=self._args.logfile,
+ filemode='w',
+ level=logging.INFO,
+ format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S')
+ else:
+ logging.basicConfig(level=logging.INFO,
+ format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S',
+ handlers=[logging.StreamHandler()])
+
+ if self._args.configfile:
+ logging.info("Read config file and overwrite arguments")
+ if not os.path.exists(self._args.configfile):
+ logging.critical("Configuration file not exsits {0}".format(self._args.configfile))
+ sys.exit(-1)
+
+ pluginconfig = configparser.ConfigParser()
+ pluginconfig.read(self._args.configfile)
+
+ self.LBSCONFIG = os.getenv("LBSCONFIG", os.getcwd())
+ self.miniserver_id = pluginconfig.get('P1DECRYPTER', 'MINISERVER_ID')
+
+ self._args.enabled = bool(int(pluginconfig.get('P1DECRYPTER', 'ENABLED')))
+ self._args.key = pluginconfig.get('P1DECRYPTER', 'KEY')
+ self._args.serial_input_port = pluginconfig.get('P1DECRYPTER', 'SERIAL_INPUT_PORT')
+ self._args.serial_input_baudrate = int(pluginconfig.get('P1DECRYPTER', 'SERIAL_INPUT_BAUDRATE'))
+ self._args.serial_input_parity = pluginconfig.get('P1DECRYPTER', 'SERIAL_INPUT_PARITY')
+ self._args.serial_input_stopbits = int(pluginconfig.get('P1DECRYPTER', 'SERIAL_INPUT_STOPBITS'))
+ self._args.mapping = base64.b64decode(
+ pluginconfig.get('P1DECRYPTER', 'MAPPING').replace('\\n', '').encode('ascii')
+ ).decode('ascii')
+ self._args.aad = pluginconfig.get('P1DECRYPTER', 'AAD')
+ self._args.send_to_udp = bool(int(pluginconfig.get('P1DECRYPTER', 'SEND_TO_UDP')))
+ self._args.udp_host = pluginconfig.get('P1DECRYPTER', 'UDP_HOST')
+ self._args.udp_port = int(pluginconfig.get('P1DECRYPTER', 'UDP_PORT'))
+ self._args.send_to_serial_port = bool(int(pluginconfig.get('P1DECRYPTER', 'SEND_TO_SERIAL_PORT')))
+ self._args.serial_output_port = pluginconfig.get('P1DECRYPTER', 'SERIAL_OUTPUT_PORT')
+ self._args.serial_output_baudrate = int(pluginconfig.get('P1DECRYPTER', 'SERIAL_OUTPUT_BAUDRATE'))
+ self._args.serial_output_parity = pluginconfig.get('P1DECRYPTER', 'SERIAL_OUTPUT_PARITY')
+ self._args.serial_output_stopbits = int(pluginconfig.get('P1DECRYPTER', 'SERIAL_OUTPUT_STOPBITS'))
+ self._args.raw = bool(int(pluginconfig.get('P1DECRYPTER', 'RAW')))
+ self._args.verbose = bool(int(pluginconfig.get('P1DECRYPTER', 'VERBOSE')))
+ else:
+ self._args.enabled = 1
+
+ if self._args.verbose:
+ logging.getLogger().setLevel(logging.DEBUG)
+
+ logging.debug("Arguments: {0}".format(self._args))
+ logging.info("Arguments and config processed")
+
+ if self._args.enabled == "0":
+ logging.warning("P1 Decrypter is not enabled in configuration file. exit")
+ sys.exit(-1)
+
+ self.miniserver()
+
+ def miniserver(self):
+
+ if not self._args.udp_host and self._args.send_to_udp:
+ if not self.miniserver_id:
+ logging.error("No UDP Host or Miniserver ID is set.")
+ sys.exit(-1)
+
+ config_path = os.path.join(self.LBSCONFIG, "general.json")
+ logging.info("Try load Miniserver system configuration file {0}".format(config_path))
+ with open(config_path, "r") as config_path_handle:
+ self.general_json = json.load(config_path_handle)
+
+ logging.info("Check if miniserver exists in {0}".format(config_path))
+ if not self.miniserver_id in self.general_json["Miniserver"].keys():
+ logging.critical(
+ "Miniserver with id {0} is not configured in {1}".format(self.miniserver_id, config_path))
+ sys.exit(-1)
+
+ self._args.udp_host = self.general_json["Miniserver"][self.miniserver_id]["Ipaddress"]
+
+ logging.info("Miniserver ip address: {0}".format(self._args.udp_host))
+
+ self.connect()
+ logging.info("Start processing incoming data.")
+ while True:
+ self.process()
+
+ def connect(self):
+ logging.info("Connect to serial input port")
+
+ try:
+ self._connection = serial.Serial(
+ port=self._args.serial_input_port,
+ baudrate=self._args.serial_input_baudrate,
+ parity=self._args.serial_input_parity,
+ stopbits=self._args.serial_input_stopbits
+ )
+ except Exception as e:
+ logging.error("Connection failed: {0}".format(e))
+ sys.exit(-1)
+
+ def process(self):
+ hex_input = binascii.hexlify(self._connection.read())
+
+ if self._state == self.STATE_IGNORING:
+ if hex_input == b'db':
+ logging.debug("STATE_IGNORING: Start byte has been detected. ({0})".format(hex_input))
+ self._state = self.STATE_STARTED
+ self._buffer = b""
+ self._buffer_length = 1
+ self._system_title_length = 0
+ self._system_title = b""
+ self._data_length = 0
+ self._data_length_bytes = b""
+ self._frame_counter = b""
+ self._payload = b""
+ self._gcm_tag = b""
+ else:
+ return
+ elif self._state == self.STATE_STARTED:
+ logging.debug("STATE_HAS_SYSTEM_TITLE_LENGTH: Read length of system title. ({0})".format(hex_input))
+ self._state = self.STATE_HAS_SYSTEM_TITLE_LENGTH
+ self._system_title_length = int(hex_input, 16)
+ self._buffer_length = self._buffer_length + 1
+ self._next_state = 2 + self._system_title_length # start bytes + system title length
+ elif self._state == self.STATE_HAS_SYSTEM_TITLE_LENGTH:
+ logging.debug("STATE_HAS_SYSTEM_TITLE_LENGTH: Read system title ({0})".format(hex_input))
+ if self._buffer_length > self._next_state:
+ self._system_title += hex_input
+ self._state = self.STATE_HAS_SYSTEM_TITLE
+ self._next_state = self._next_state + 2 # read two more bytes
+ else:
+ self._system_title += hex_input
+ elif self._state == self.STATE_HAS_SYSTEM_TITLE:
+ logging.debug("STATE_HAS_SYSTEM_TITLE: Read additional byte after system title. ({0})".format(hex_input))
+ if hex_input == b'82':
+ self._next_state = self._next_state + 1
+ self._state = self.STATE_HAS_SYSTEM_TITLE_SUFFIX # Ignore separator byte
+ else:
+ logging.warning("Expected 0x82 separator byte not found, dropping frame ({0})".format(hex_input))
+ self._state = self.STATE_IGNORING
+ elif self._state == self.STATE_HAS_SYSTEM_TITLE_SUFFIX:
+ logging.debug("STATE_HAS_SYSTEM_TITLE_SUFFIX: Read length of remaining data. ({0})".format(hex_input))
+ if self._buffer_length > self._next_state:
+ self._data_length_bytes += hex_input
+ self._data_length = int(self._data_length_bytes, 16)
+ self._state = self.STATE_HAS_DATA_LENGTH
+ else:
+ self._data_length_bytes += hex_input
+ elif self._state == self.STATE_HAS_DATA_LENGTH:
+ logging.debug("STATE_HAS_DATA_LENGTH: Read additional byte after data. ({0})".format(hex_input))
+ self._state = self.STATE_HAS_SEPARATOR # Ignore separator byte
+ self._next_state = self._next_state + 1 + 4 # separator byte + 4 bytes for framecounter
+ elif self._state == self.STATE_HAS_SEPARATOR:
+ logging.debug("STATE_HAS_DATA_LENGTH: Read frame counter. ({0})".format(hex_input))
+ if self._buffer_length > self._next_state:
+ self._frame_counter += hex_input
+ self._state = self.STATE_HAS_FRAME_COUNTER
+ self._next_state = self._next_state + self._data_length - 17
+ else:
+ self._frame_counter += hex_input
+ elif self._state == self.STATE_HAS_FRAME_COUNTER:
+ logging.debug("STATE_HAS_FRAME_COUNTER: Read payload. ({0})".format(hex_input))
+ if self._buffer_length > self._next_state:
+ self._payload += hex_input
+ self._state = self.STATE_HAS_PAYLOAD
+ self._next_state = self._next_state + 12
+ else:
+ self._payload += hex_input
+ elif self._state == self.STATE_HAS_PAYLOAD:
+ logging.debug("STATE_HAS_PAYLOAD: Switch back to STATE_IGNORING and wait for a new start byte. ({0})".format(hex_input))
+ if self._buffer_length > self._next_state:
+ self._gcm_tag += hex_input
+ self._state = self.STATE_DONE
+ else:
+ self._gcm_tag += hex_input
+
+ self._buffer += hex_input
+ self._buffer_length = self._buffer_length + 1
+
+ if self._state == self.STATE_DONE:
+ self.decrypt()
+ self._state = self.STATE_IGNORING
+
+ #
+ def decrypt(self):
+ logging.debug("Full telegram received, start decryption.")
+
+ cipher = AES.new(
+ binascii.unhexlify(self._args.key),
+ AES.MODE_GCM,
+ binascii.unhexlify(self._system_title + self._frame_counter),
+ mac_len=12
+ )
+ cipher.update(binascii.unhexlify(self._args.aad))
+ self.mapping(cipher.decrypt(binascii.unhexlify(self._payload)))
+
+ def mapping(self, decryption):
+ logging.debug("Decryption done. Extract data by mapping configuration: {0}".format(decryption))
+
+ output = ""
+
+ if self._args.raw:
+ logging.debug("Raw output is enabled. Mapping extraction stopped. Send complete telegram")
+ output = decryption;
+ else:
+ input_multi_array = []
+ for i in self._args.mapping.splitlines():
+ input_multi_array.append([i.split(',')[0].strip().strip("'"), i.split(',')[1].strip().strip("'")])
+
+ for i in input_multi_array:
+ output += i[0] + ":" + re.search(i[1], decryption.decode()).group(0) + "\n"
+
+ output = output.encode()
+
+ if self._args.send_to_udp:
+ self.send_to_udb(output)
+
+ if self._args.send_to_serial_port:
+ self.send_to_serial_port(output)
+
+ def send_to_serial_port(self, output):
+ logging.debug("Send the decrypted data to output serial port: {0}".format(output.decode()))
+ serial_port = serial.Serial(
+ port=self._args.serial_output_port,
+ baudrate=self._args.serial_output_baudrate,
+ parity=self._args.serial_output_parity,
+ stopbits=self._args.serial_output_stopbits
+ )
+ serial_port.write(output)
+ serial_port.close()
+
+ def send_to_udb(self, output):
+ logging.debug("Send the decrypted data over udp: {0}".format(output.decode()))
+ connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ res = connection.sendto(output, (self._args.udp_host, self._args.udp_port))
+ connection.close()
+
+ if res != output.__len__():
+ logging.error("Sent bytes not matching. Expected {0} to be {1}".format(output.decode().__len__(), res))
+
+
+if __name__ == '__main__':
+ smarty_proxy = P1decrypter()
+ smarty_proxy.main()
diff --git a/config/p1decrypter-default.cfg b/config/p1decrypter-default.cfg
new file mode 100644
index 0000000..240178c
--- /dev/null
+++ b/config/p1decrypter-default.cfg
@@ -0,0 +1,20 @@
+[P1DECRYPTER]
+ENABLED=0
+KEY=0000112233445566778899AABBCCDDEEFF
+SERIAL_INPUT_PORT=/dev/ttyUSB0
+SERIAL_INPUT_BAUDRATE=115200
+SERIAL_INPUT_PARITY=N
+SERIAL_INPUT_STOPBITS=1
+MAPPING=JzEtMDoxLjguMCcsJyg/PD0xLTA6MS44LjBcKCkuKj8oPz1cKldoKScNCicxLTA6MS43LjAnLCco\\nPzw9MS0wOjEuNy4wXCgpLio/KD89XCpXKScNCicxLTA6Mi44LjAnLCcoPzw9MS0wOjIuOC4wXCgp\\nLio/KD89XCpXaCknDQonMS0wOjIuNy4wJywnKD88PTEtMDoyLjcuMFwoKS4qPyg/PVwqVykn\\n
+AAD=3000112233445566778899AABBCCDDEEFF
+SEND_TO_UDP=1
+MINISERVER_ID=1
+UDP_HOST=
+UDP_PORT=54321
+SEND_TO_SERIAL_PORT=0
+SERIAL_OUTPUT_PORT=/dev/p1decrypter
+SERIAL_OUTPUT_BAUDRATE=115200
+SERIAL_OUTPUT_PARITY=N
+SERIAL_OUTPUT_STOPBITS=1
+RAW=0
+VERBOSE=0
\ No newline at end of file
diff --git a/config/p1decrypter.cfg b/config/p1decrypter.cfg
new file mode 100644
index 0000000..240178c
--- /dev/null
+++ b/config/p1decrypter.cfg
@@ -0,0 +1,20 @@
+[P1DECRYPTER]
+ENABLED=0
+KEY=0000112233445566778899AABBCCDDEEFF
+SERIAL_INPUT_PORT=/dev/ttyUSB0
+SERIAL_INPUT_BAUDRATE=115200
+SERIAL_INPUT_PARITY=N
+SERIAL_INPUT_STOPBITS=1
+MAPPING=JzEtMDoxLjguMCcsJyg/PD0xLTA6MS44LjBcKCkuKj8oPz1cKldoKScNCicxLTA6MS43LjAnLCco\\nPzw9MS0wOjEuNy4wXCgpLio/KD89XCpXKScNCicxLTA6Mi44LjAnLCcoPzw9MS0wOjIuOC4wXCgp\\nLio/KD89XCpXaCknDQonMS0wOjIuNy4wJywnKD88PTEtMDoyLjcuMFwoKS4qPyg/PVwqVykn\\n
+AAD=3000112233445566778899AABBCCDDEEFF
+SEND_TO_UDP=1
+MINISERVER_ID=1
+UDP_HOST=
+UDP_PORT=54321
+SEND_TO_SERIAL_PORT=0
+SERIAL_OUTPUT_PORT=/dev/p1decrypter
+SERIAL_OUTPUT_BAUDRATE=115200
+SERIAL_OUTPUT_PARITY=N
+SERIAL_OUTPUT_STOPBITS=1
+RAW=0
+VERBOSE=0
\ No newline at end of file
diff --git a/cron/cron.05min b/cron/cron.05min
new file mode 100644
index 0000000..f061740
--- /dev/null
+++ b/cron/cron.05min
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# This is a sample cron file. According to it's name it will go to
+# ~/system/cron/cron.10min. You may also let your Pluginscript create a
+# symbolic link dynamically in ~/system/cron/cron.10min which links to your
+# cron-script instead (which is prefered). Use NAME from
+# /data/system/plugindatabase.dat in that case as scriptname! Otherwise the
+# cron script will not be uninstalled cleanly.
+
+# Will be executed as user "loxberry".
+
+if ! pgrep -f p1decrypter.py >/dev/null && [ -e REPLACELBPBINDIR/p1decrypter.py ]
+then
+ /usr/bin/python3 REPLACELBPBINDIR/p1decrypter.py KEY --logfile=REPLACELBPLOGDIR/p1decrypter.log --configfile=REPLACELBPCONFIGDIR/p1decrypter.cfg >> REPLACELBPLOGDIR/p1decrypter.log 2>&1
+fi
\ No newline at end of file
diff --git a/dpkg/apt b/dpkg/apt
new file mode 100644
index 0000000..81257d6
--- /dev/null
+++ b/dpkg/apt
@@ -0,0 +1,6 @@
+# These packages will be installed by apt-get -y install PACKAGENAME
+# One line per package, use exact packagename as you would do for apt-get.
+#
+python3
+python3-serial
+python3-pycryptodome
\ No newline at end of file
diff --git a/icons/icon_128.png b/icons/icon_128.png
new file mode 100644
index 0000000..26a3a69
Binary files /dev/null and b/icons/icon_128.png differ
diff --git a/icons/icon_256.png b/icons/icon_256.png
new file mode 100644
index 0000000..0e7ef7b
Binary files /dev/null and b/icons/icon_256.png differ
diff --git a/icons/icon_512.png b/icons/icon_512.png
new file mode 100644
index 0000000..3653499
Binary files /dev/null and b/icons/icon_512.png differ
diff --git a/icons/icon_64.png b/icons/icon_64.png
new file mode 100644
index 0000000..e1ff60a
Binary files /dev/null and b/icons/icon_64.png differ
diff --git a/plugin.cfg b/plugin.cfg
new file mode 100644
index 0000000..9a5bc92
--- /dev/null
+++ b/plugin.cfg
@@ -0,0 +1,80 @@
+[AUTHOR]
+# You can also use a Team/Projekt Name here and a generic email address
+# like info@..., BUT NEVER CHANGE this information in future updates! It
+# will be used to identify your Plugin, handle updates etc. If you change
+# this information, LoxBerry could not identify your plugin and handle it as
+# a different one - therefore updates will fail.
+NAME=Daniel Schwab
+EMAIL=p1decrypter@gmail.com
+
+[PLUGIN]
+# The version of your plugin - important if you would like to write an
+# upgrade script. Use a correct syntax, which is supported by LoxBerry:
+# More info: http://www.loxwiki.eu/x/LYG3AQ
+VERSION=1.0.0
+
+# Short name and prefered subfolder of your Plugin (do not use blanks - they
+# will be filtered - and use lowercase only)! Used for script names in
+# daemon or cron (NAME) and as unique installation folder. If these names
+# already exist on the installation system, we will add 01, 02, 03 and so
+# on. Therefore your script should check THESE TWO VARIABLES for figuring
+# out subfolder and scriptnames! You will find this information in
+# /data/system/plugindatabase.dat after installation! BUT NEVER CHANGE this
+# information in future updates! It will be used to identify your Plugin,
+# handle updates etc. If you change this information, Loxberry could not
+# identify your plugin and will handle it as a different one - therefore
+# updates will definetely fail.
+NAME=p1decrypter
+FOLDER=p1decrypter
+
+# Friendly Long Name of your Plugin - 25 Characters maximum! All others maybe
+# replaced by "...". You can use blanks, uppercase/lowercase etc.
+TITLE=P1 Decrypter
+
+[AUTOUPDATE]
+# If your plugin offers automatic updates, please enable the following option.
+# Details here: http://www.loxwiki.eu/x/WoG3AQ
+AUTOMATIC_UPDATES=true
+
+# This is the URL to your release.cfg file. This file will be checked for
+# new releases if the user eneables autoupdates. If the version number
+# given in the release.cfg file is newer than the installed one, the
+# plugin archive will be downloaded from the URL given in the release.cfg file
+# and will be installed automatically
+RELEASECFG=https://raw.githubusercontent.com/metrophos/LoxBerry-Plugin-P1-Decrypter/master/release.cfg
+
+# This is the URL to your prerelease.cfg file. This file will be checked for
+# new prereleases if the user enables autoupdates for prereleases. If the
+# version number given in the release.cfg file is newer than the installed
+# one, the plugin archive will be downloaded from the URL given in the
+# release.cfg file and will be installed automatically
+PRERELEASECFG=https://raw.githubusercontent.com/metrophos/LoxBerry-Plugin-P1-Decrypter/master/prerelease.cfg
+
+[SYSTEM]
+# If a reboot is needed after the plugin was installed, enable the following
+# option:
+REBOOT=false
+
+# If your Plugin runs only on special LoxBerry Versions, please set the
+# following options. If you plugin is compatible with all versions or at least
+# with all future versions, please set this to false or leave it empty..
+# Note! If you use the new Plugin Interface V2 - I think you will, because you
+# currently read THIS file ;-) - please set the Minimum version to 0.3.0!
+LB_MINIMUM=0.3.1
+LB_MAXIMUM=false
+
+# If your plugin runs only on a special architecture (e.g. if you use the GPIOs
+# on a Raspberry platform), please set the architecture here. You can seperate
+# different architectures with a comma. Set to false or leave it empty if your
+# plugin do not use any special features of an architecture.
+# PUT in QUOTES ""!!!
+# Please check http://www.loxwiki.eu:80/x/VoU_AQ section 5.1 for supported
+# architectures and strings you should use here.
+ARCHITECTURE="raspberry,x86"
+
+# If you are using the LoxBerry::Log Modul in PHP or Perl and you would like to use User-defined loglevels,
+# enable this option. If enabled, the user will be able to choose a loglevel in the Plugin Management Widget.
+CUSTOM_LOGLEVELS=false
+
+# Plugin Interface. Do not change this if you are not knowing what you are doing!
+INTERFACE=2.0
diff --git a/postupgrade.sh b/postupgrade.sh
new file mode 100644
index 0000000..6181a86
--- /dev/null
+++ b/postupgrade.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Bash script which is executed in case of an update (if this plugin is already
+# installed on the system). This script is executed as very last step (*AFTER*
+# postinstall) and can be for example used to save back or convert saved
+# userfiles from /tmp back to the system. Use with caution and remember, that
+# all systems may be different!
+#
+# Exit code must be 0 if executed successfull.
+# Exit code 1 gives a warning but continues installation.
+# Exit code 2 cancels installation.
+#
+# Will be executed as user "loxberry".
+#
+# You can use all vars from /etc/environment in this script.
+#
+# We add 5 additional arguments when executing this script:
+# command
+#
+# For logging, print to STDOUT. You can use the following tags for showing
+# different colorized information during plugin installation:
+#
+# This was ok!"
+# This is just for your information."
+# This is a warning!"
+# This is an error!"
+# This is a fail!"
+
+# To use important variables from command line use the following code:
+COMMAND=$0 # Zero argument is shell command
+PTEMPDIR=$1 # First argument is temp folder during install
+PSHNAME=$2 # Second argument is Plugin-Name for scipts etc.
+PDIR=$3 # Third argument is Plugin installation folder
+PVERSION=$4 # Forth argument is Plugin version
+#LBHOMEDIR=$5 # Comes from /etc/environment now. Fifth argument is
+ # Base folder of LoxBerry
+PTEMPPATH=$6 # Sixth argument is full temp path during install (see also $1)
+
+# Combine them with /etc/environment
+PCGI=$LBPCGI/$PDIR
+PHTML=$LBPHTML/$PDIR
+PTEMPL=$LBPTEMPL/$PDIR
+PDATA=$LBPDATA/$PDIR
+PLOG=$LBPLOG/$PDIR # Note! This is stored on a Ramdisk now!
+PCONFIG=$LBPCONFIG/$PDIR
+PSBIN=$LBPSBIN/$PDIR
+PBIN=$LBPBIN/$PDIR
+
+#echo -n " Current working folder is: "
+#pwd
+#echo " Command is: $COMMAND"
+#echo " Temporary folder is: $PTEMPDIR"
+#echo " (Short) Name is: $PSHNAME"
+#echo " Installation folder is: $PDIR"
+#echo " Plugin version is: $PVERSION"
+#echo " Plugin CGI folder is: $PCGI"
+#echo " Plugin HTML folder is: $PHTML"
+#echo " Plugin Template folder is: $PTEMPL"
+#echo " Plugin Data folder is: $PDATA"
+#echo " Plugin Log folder (on RAMDISK!) is: $PLOG"
+#echo " Plugin CONFIG folder is: $PCONFIG"
+
+echo " Copy back existing config files"
+cp -v -r /tmp/$ARGV1/_upgrade/config/$ARGV3/* $ARGV5/config/plugins/$ARGV3/
+
+# echo " Adding new config parameters"
+# grep -q -F "VERBOSE=" $ARGV5/config/plugins/$ARGV3/p1decrypter.cfg || echo "VERBOSE=0" >> $ARGV5/config/plugins/$ARGV3/p1decrypter.cfg
+
+echo " Copy back existing log files"
+cp -v -r /tmp/$ARGV1/_upgrade/log/$ARGV3/* $ARGV5/log/plugins/$ARGV3/
+
+echo " Remove temporary folders"
+rm -rf /tmp/$ARGV1/_upgrade
+
+exit 0
diff --git a/prerelease.cfg b/prerelease.cfg
new file mode 100644
index 0000000..f94208f
--- /dev/null
+++ b/prerelease.cfg
@@ -0,0 +1,15 @@
+[AUTOUPDATE]
+# This file is used if you would like to provide automatic updates. Put
+# this file into your repo and give a link to this file in your plugin.cfg
+# If you would like to release an update, edit VERSION here and give
+# the donwload link here
+
+
+# Version of the new release
+VERSION=1.0.0
+
+# Download URL of the ZIP Archive
+ARCHIVEURL=https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/archive/1.0.0.zip
+
+# URL for further information about this release
+INFOURL=https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/releases
diff --git a/preupgrade.sh b/preupgrade.sh
new file mode 100644
index 0000000..61032ed
--- /dev/null
+++ b/preupgrade.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+# Shell script which is executed in case of an update (if this plugin is already
+# installed on the system). This script is executed as very first step (*BEFORE*
+# preinstall.sh) and can be used e.g. to save existing configfiles to /tmp
+# during installation. Use with caution and remember, that all systems may be
+# different!
+#
+# Exit code must be 0 if executed successfull.
+# Exit code 1 gives a warning but continues installation.
+# Exit code 2 cancels installation.
+#
+# Will be executed as user "loxberry".
+#
+# You can use all vars from /etc/environment in this script.
+#
+# We add 5 additional arguments when executing this script:
+# command
+#
+# For logging, print to STDOUT. You can use the following tags for showing
+# different colorized information during plugin installation:
+#
+# This was ok!"
+# This is just for your information."
+# This is a warning!"
+# This is an error!"
+# This is a fail!"
+
+# To use important variables from command line use the following code:
+COMMAND=$0 # Zero argument is shell command
+PTEMPDIR=$1 # First argument is temp folder during install
+PSHNAME=$2 # Second argument is Plugin-Name for scipts etc.
+PDIR=$3 # Third argument is Plugin installation folder
+PVERSION=$4 # Forth argument is Plugin version
+#LBHOMEDIR=$5 # Comes from /etc/environment now. Fifth argument is
+ # Base folder of LoxBerry
+PTEMPPATH=$6 # Sixth argument is full temp path during install (see also $1)
+
+# Combine them with /etc/environment
+PCGI=$LBPCGI/$PDIR
+PHTML=$LBPHTML/$PDIR
+PTEMPL=$LBPTEMPL/$PDIR
+PDATA=$LBPDATA/$PDIR
+PLOG=$LBPLOG/$PDIR # Note! This is stored on a Ramdisk now!
+PCONFIG=$LBPCONFIG/$PDIR
+PSBIN=$LBPSBIN/$PDIR
+PBIN=$LBPBIN/$PDIR
+
+#echo -n " Current working folder is: "
+#pwd
+#echo " Command is: $COMMAND"
+#echo " Temporary folder is: $PTEMPDIR"
+#echo " (Short) Name is: $PSHNAME"
+#echo " Installation folder is: $PDIR"
+#echo " Plugin version is: $PVERSION"
+#echo " Plugin CGI folder is: $PCGI"
+#echo " Plugin HTML folder is: $PHTML"
+#echo " Plugin Template folder is: $PTEMPL"
+#echo " Plugin Data folder is: $PDATA"
+#echo " Plugin Log folder (on RAMDISK!) is: $PLOG"
+#echo " Plugin CONFIG folder is: $PCONFIG"
+
+echo " Creating temporary folders for upgrading"
+mkdir -p /tmp/$ARGV1/_upgrade/config
+mkdir -p /tmp/$ARGV1/_upgrade/log
+
+echo " Backup existing config files"
+cp -v -r $ARGV5/config/plugins/$ARGV3/ /tmp/$ARGV1/_upgrade/config
+
+echo " Backup existing log files"
+cp -v -r $ARGV5/log/plugins/$ARGV3/ /tmp/$ARGV1/_upgrade/log
+
+exit 0
diff --git a/release.cfg b/release.cfg
new file mode 100644
index 0000000..8c50b1b
--- /dev/null
+++ b/release.cfg
@@ -0,0 +1,14 @@
+[AUTOUPDATE]
+# This file is used if you would like to provide automatic updates. Put
+# this file into your repo and give a link to this file in your plugin.cfg
+# If you would like to release an update, edit VERSION here and give
+# the donwload link here
+
+# Version of the new release
+VERSION=1.0.3
+
+# Download URL of the ZIP Archive
+ARCHIVEURL=https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/archive/1.0.0.zip
+
+# URL for further information about this release
+INFOURL=https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter/releases
diff --git a/templates/content.html b/templates/content.html
new file mode 100644
index 0000000..603e924
--- /dev/null
+++ b/templates/content.html
@@ -0,0 +1,167 @@
+
+
+
\ No newline at end of file
diff --git a/uninstall/uninstall b/uninstall/uninstall
new file mode 100644
index 0000000..00f49f5
--- /dev/null
+++ b/uninstall/uninstall
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# Bashscript which is executed by bash when uninstalling the plugin
+# Use with caution and remember, that all systems may be different!
+#
+# Exit code must be 0 if executed successfull.
+# Exit code 1 gives a warning but continues deinstallation.
+#
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# Will be executed as user "root".
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#
+# You can use all vars from /etc/environment in this script.
+#
+# We add 5 additional arguments when executing this script:
+# command
+#
+# For logging, print to STDOUT. You can use the following tags for showing
+# different colorized information during plugin installation:
+#
+# This was ok!"
+# This is just for your information."
+# This is a warning!"
+# This is an error!"
+# This is a fail!"
+
+# To use important variables from command line use the following code:
+#COMMAND=$0 # Zero argument is shell command
+#PTEMPDIR=$1 # First argument is temp folder during install
+#PSHNAME=$2 # Second argument is Plugin-Name for scipts etc.
+#PDIR=$3 # Third argument is Plugin installation folder
+#PVERSION=$4 # Forth argument is Plugin version
+#LBHOMEDIR=$5 # Comes from /etc/environment now. Fifth argument is
+ # Base folder of LoxBerry
+
+# Combine them with /etc/environment
+#PCGI=$LBPCGI/$PDIR
+#PHTML=$LBPHTML/$PDIR
+#PTEMPL=$LBPTEMPL/$PDIR
+#PDATA=$LBPDATA/$PDIR
+#PLOG=$LBPLOG/$PDIR # Note! This is stored on a Ramdisk now!
+#PCONFIG=$LBPCONFIG/$PDIR
+#PSBIN=$LBPSBIN/$PDIR
+#PBIN=$LBPBIN/$PDIR
+#
+#echo " Command is: $COMMAND"
+#echo " Temporary folder is: $TEMPDIR"
+#echo " (Short) Name is: $PSHNAME"
+#echo " Installation folder is: $ARGV3"
+#echo " Plugin version is: $ARGV4"
+#echo " Plugin CGI folder is: $PCGI"
+#echo " Plugin HTML folder is: $PHTML"
+#echo " Plugin Template folder is: $PTEMPL"
+#echo " Plugin Data folder is: $PDATA"
+#echo " Plugin Log folder (on RAMDISK!) is: $PLOG"
+#echo " Plugin CONFIG folder is: $PCONFIG"
+#echo " Plugin SBIN folder is: $PSBIN"
+#echo " Plugin BIN folder is: $PBIN"
+
+pkill -9 -f p1decrypter.py
+
+# Exit with Status 0
+exit 0
\ No newline at end of file
diff --git a/webfrontend/htmlauth/index.cgi b/webfrontend/htmlauth/index.cgi
new file mode 100644
index 0000000..f7296a7
--- /dev/null
+++ b/webfrontend/htmlauth/index.cgi
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use CGI;
+use LoxBerry::System;
+use LoxBerry::Web;
+use MIME::Base64;
+use Config::Simple;
+
+## on/off switch values
+my @switch = ('0', '1');
+my %switchLabels = (
+ '0' => 'No',
+ '1' => 'Yes'
+);
+
+# get configs
+my $p1decrypterCfg = new Config::Simple("$lbpconfigdir/p1decrypter.cfg");
+my $p1decrypterDefaultCfg = new Config::Simple("$lbpconfigdir/p1decrypter-default.cfg");
+my $generalCfg = new Config::Simple("$lbsconfigdir/general.cfg");
+my $plugindata = LoxBerry::System::plugindata();
+
+# get request values
+my $cgi = CGI->new;
+$cgi->import_names('R');
+
+# save settings to p1decrypter.cfg
+if ($R::action eq "Save & Restart") {
+ $p1decrypterCfg->param('P1DECRYPTER.ENABLED', $R::enabled);
+ $p1decrypterCfg->param('P1DECRYPTER.KEY', $R::key);
+ $p1decrypterCfg->param('P1DECRYPTER.MAPPING', encode_base64($R::mapping));
+ $p1decrypterCfg->param('P1DECRYPTER.MINISERVER_ID', $R::miniserver_id);
+ $p1decrypterCfg->param('P1DECRYPTER.UDP_PORT', $R::upd_port);
+
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PORT', $R::serial_input_port);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_BAUDRATE', $R::serial_input_baudrate);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PARITY', $R::serial_input_parity);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_STOPBITS', $R::serial_input_stopbits);
+ $p1decrypterCfg->param('P1DECRYPTER.AAD', $R::aad);
+ $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_UDP', $R::send_to_udp);
+ $p1decrypterCfg->param('P1DECRYPTER.UDP_HOST', $R::udp_host);
+ $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_SERIAL_PORT', $R::send_to_serial_port);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PORT', $R::serial_output_port);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_BAUDRATE', $R::serial_output_baudrate);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PARITY', $R::serial_output_parity);
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_STOPBITS', $R::serial_output_stopbits);
+ $p1decrypterCfg->param('P1DECRYPTER.RAW', $R::raw);
+ $p1decrypterCfg->param('P1DECRYPTER.VERBOSE', $R::verbose);
+
+ $p1decrypterCfg->save();
+}
+
+# reset values to p1decrypter-default.cfg
+if ($R::action eq "Reset default configruation") {
+ $p1decrypterCfg->param('P1DECRYPTER.ENABLED', $p1decrypterDefaultCfg->param('P1DECRYPTER.ENABLED'));
+ $p1decrypterCfg->param('P1DECRYPTER.KEY', $p1decrypterDefaultCfg->param('P1DECRYPTER.KEY'));
+ $p1decrypterCfg->param('P1DECRYPTER.MAPPING', $p1decrypterDefaultCfg->param('P1DECRYPTER.MAPPING'));
+ $p1decrypterCfg->param('P1DECRYPTER.MINISERVER_ID', $p1decrypterDefaultCfg->param('P1DECRYPTER.MINISERVER_ID'));
+ $p1decrypterCfg->param('P1DECRYPTER.UDP_PORT', $p1decrypterDefaultCfg->param('P1DECRYPTER.UDP_PORT'));
+
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PORT', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_INPUT_PORT'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_BAUDRATE', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_INPUT_BAUDRATE'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PARITY', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_INPUT_PARITY'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_STOPBITS', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_INPUT_STOPBITS'));
+ $p1decrypterCfg->param('P1DECRYPTER.AAD', $p1decrypterDefaultCfg->param('P1DECRYPTER.AAD'));
+ $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_UDP', $p1decrypterDefaultCfg->param('P1DECRYPTER.SEND_TO_UDP'));
+ $p1decrypterCfg->param('P1DECRYPTER.UDP_HOST', $p1decrypterDefaultCfg->param('P1DECRYPTER.UDP_HOST'));
+ $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_SERIAL_PORT', $p1decrypterDefaultCfg->param('P1DECRYPTER.SEND_TO_SERIAL_PORT'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PORT', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PORT'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_BAUDRATE', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_OUTPUT_BAUDRATE'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PARITY', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PARITY'));
+ $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_STOPBITS', $p1decrypterDefaultCfg->param('P1DECRYPTER.SERIAL_OUTPUT_STOPBITS'));
+ $p1decrypterCfg->param('P1DECRYPTER.RAW', $p1decrypterDefaultCfg->param('P1DECRYPTER.RAW'));
+ $p1decrypterCfg->param('P1DECRYPTER.VERBOSE', $p1decrypterDefaultCfg->param('P1DECRYPTER.VERBOSE'));
+
+ $p1decrypterCfg->save();
+}
+
+# read settings from p1decrypter.cfg
+$cgi->delete_all();
+$R::enabled = $p1decrypterCfg->param('P1DECRYPTER.ENABLED');
+$R::key = $p1decrypterCfg->param('P1DECRYPTER.KEY');
+$R::mapping = decode_base64($p1decrypterCfg->param('P1DECRYPTER.MAPPING'));
+$R::miniserver_id = $p1decrypterCfg->param('P1DECRYPTER.MINISERVER_ID');
+$R::upd_port = $p1decrypterCfg->param('P1DECRYPTER.UDP_PORT');
+
+$R::serial_input_port = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PORT');
+$R::serial_input_baudrate = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_BAUDRATE');
+$R::serial_input_parity = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_PARITY');
+$R::serial_input_stopbits = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_INPUT_STOPBITS');
+$R::aad = $p1decrypterCfg->param('P1DECRYPTER.AAD');
+$R::send_to_udp = $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_UDP');
+$R::udp_host = $p1decrypterCfg->param('P1DECRYPTER.UDP_HOST');
+$R::send_to_serial_port = $p1decrypterCfg->param('P1DECRYPTER.SEND_TO_SERIAL_PORT');
+$R::serial_output_port = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PORT');
+$R::serial_output_baudrate = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_BAUDRATE');
+$R::serial_output_parity = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_PARITY');
+$R::serial_output_stopbits = $p1decrypterCfg->param('P1DECRYPTER.SERIAL_OUTPUT_STOPBITS');
+$R::raw = $p1decrypterCfg->param('P1DECRYPTER.RAW');
+$R::verbose = $p1decrypterCfg->param('P1DECRYPTER.VERBOSE');
+
+# restart p1decrypter
+if ($R::action eq "Save & Restart" || $R::action eq "Reset default configruation") {
+ if ($R::enabled eq "1") {
+ qx(pkill -9 -f p1decrypter.py);
+ qx(/bin/sh $lbhomedir/system/cron/cron.05min/$plugindata->{PLUGINDB_NAME} > /dev/null 2>&1 &);
+ sleep(2);
+ }
+ else {
+ qx(pkill -9 -f p1decrypter.py);
+ }
+}
+
+#--------------------------------------------------
+#--------------------------------------------------
+
+# create html elements
+my $template = HTML::Template->new(
+ filename => "$lbptemplatedir/content.html",
+ associate => $cgi,
+);
+
+## ENABLED switch
+$template->param(ENABLED => $cgi->popup_menu(
+ -name => 'enabled',
+ -values => \@switch,
+ -labels => \%switchLabels,
+ -default => $R::enabled
+));
+
+## KEY textfield
+$template->param(KEY => $cgi->textfield(-name => 'key', -default => $R::key));
+
+## MAPPING textarea
+$template->param(MAPPING => $cgi->textarea(-name => 'mapping', -default => $R::mapping));
+
+## MINISERVER_ID selection
+my @miniserverIds = ();
+my %miniserverLabels = ();
+for (my $i = 1; $i <= $generalCfg->param('BASE.MINISERVERS'); $i++) {
+ push @miniserverIds, $i;
+ $miniserverLabels{ $i } = $generalCfg->param("MINISERVER$i.NAME") . " (" . ($generalCfg->param("MINISERVER$i.IPADDRESS")) . ")";
+};
+$template->param(MINISERVER_ID => $cgi->popup_menu(
+ -name => 'miniserver_id',
+ -values => \@miniserverIds,
+ -labels => \%miniserverLabels,
+ -default => $R::miniserver_id
+));
+
+## UDP_PORT textfield
+$template->param(UDP_PORT => $cgi->textfield(-name => 'upd_port', -default => $R::upd_port));
+
+## SERIAL_INPUT_PORT textfield
+$template->param(SERIAL_INPUT_PORT => $cgi->textfield(-name => 'serial_input_port', -default => $R::serial_input_port));
+
+## SERIAL_INPUT_BAUDRATE textfield
+$template->param(SERIAL_INPUT_BAUDRATE => $cgi->textfield(-name => 'serial_input_baudrate', -default => $R::serial_input_baudrate));
+
+## SERIAL_INPUT_PARITY textfield
+$template->param(SERIAL_INPUT_PARITY => $cgi->textfield(-name => 'serial_input_parity', -default => $R::serial_input_parity));
+
+## SERIAL_INPUT_STOPBITS textfield
+$template->param(SERIAL_INPUT_STOPBITS => $cgi->textfield(-name => 'serial_input_stopbits', -default => $R::serial_input_stopbits));
+
+## AAD textfield
+$template->param(AAD => $cgi->textfield(-name => 'aad', -default => $R::aad));
+
+## SEND_TO_UDP switch
+$template->param(SEND_TO_UDP => $cgi->popup_menu(
+ -name => 'send_to_udp',
+ -values => \@switch,
+ -labels => \%switchLabels,
+ -default => $R::send_to_udp
+));
+
+## UDP_HOST textfield
+$template->param(UDP_HOST => $cgi->textfield(-name => 'udp_host', -default => $R::udp_host));
+
+## SEND_TO_SERIAL_PORT switch
+$template->param(SEND_TO_SERIAL_PORT => $cgi->popup_menu(
+ -name => 'send_to_serial_port',
+ -values => \@switch,
+ -labels => \%switchLabels,
+ -default => $R::send_to_serial_port
+));
+
+## SERIAL_OUTPUT_PORT textfield
+$template->param(SERIAL_OUTPUT_PORT => $cgi->textfield(-name => 'serial_output_port', -default => $R::serial_output_port));
+
+## SERIAL_OUTPUT_BAUDRATE textfield
+$template->param(SERIAL_OUTPUT_BAUDRATE => $cgi->textfield(-name => 'serial_output_baudrate', -default => $R::serial_output_baudrate));
+
+## SERIAL_OUTPUT_PARITY textfield
+$template->param(SERIAL_OUTPUT_PARITY => $cgi->textfield(-name => 'serial_output_parity', -default => $R::serial_output_parity));
+
+## SERIAL_OUTPUT_STOPBITS textfield
+$template->param(SERIAL_OUTPUT_STOPBITS => $cgi->textfield(-name => 'serial_output_stopbits', -default => $R::serial_output_stopbits));
+
+## RAW switch
+$template->param(RAW => $cgi->popup_menu(
+ -name => 'raw',
+ -values => \@switch,
+ -labels => \%switchLabels,
+ -default => $R::raw
+));
+
+## VERBOSE switch
+$template->param(VERBOSE => $cgi->popup_menu(
+ -name => 'verbose',
+ -values => \@switch,
+ -labels => \%switchLabels,
+ -default => $R::verbose
+));
+
+## pid
+my $pid = trim(qx(pgrep -f p1decrypter.py));
+$pid = $pid eq "" ? "$plugindata->{PLUGINDB_TITLE} down" : "$plugindata->{PLUGINDB_TITLE} up (PID: $pid)";
+$template->param(PID => $pid);
+
+
+# write template
+LoxBerry::Web::lbheader("$plugindata->{PLUGINDB_TITLE} $plugindata->{PLUGINDB_VERSION}", "https://github.com/metrophos/LoxBerry-Plugin-P1-Decrypter");
+print $template->output();
+LoxBerry::Web::lbfooter();
+
+exit;