diff --git a/docs/use/webui.md b/docs/use/webui.md
index 24198c0..b3004a9 100644
--- a/docs/use/webui.md
+++ b/docs/use/webui.md
@@ -30,6 +30,10 @@ Ability to change the mqtt settings, if the change is unsuccessful it will rever
Ability to change the display of sensor to Metric or Imperial, and disable the WebUI Authentication
+## Bluetooth Low Energy - BLE
+
+Ability to add the default AES BLE decryption key, and multiple per-device `macaddress:aeskey` allowing for devices that cannot have their AES key changed.
+
## Logging
Ability to temporarily change the logging level.
diff --git a/main/TheengsCommon.h b/main/TheengsCommon.h
index 17a0fe8..f52cea6 100644
--- a/main/TheengsCommon.h
+++ b/main/TheengsCommon.h
@@ -63,6 +63,11 @@ extern char mqtt_topic[];
extern char gateway_name[];
extern unsigned long lastDiscovery; // Time of the last discovery to trigger automaticaly to off after DiscoveryAutoOffTimer
+#if BLEDecryptor
+extern char ble_aes[];
+extern StaticJsonDocument ble_aes_keys;
+#endif
+
extern bool enqueueJsonObject(const StaticJsonDocument& jsonDoc, int timeout);
extern bool enqueueJsonObject(const StaticJsonDocument& jsonDoc);
extern void buildTopicFromId(JsonObject& Jsondata, const char* origin);
diff --git a/main/User_config.h b/main/User_config.h
index ea5fcbf..e11e3a2 100644
--- a/main/User_config.h
+++ b/main/User_config.h
@@ -652,6 +652,18 @@ bool isAduplicateSignal(uint64_t);
void storeSignalValue(uint64_t);
#endif
+#ifdef ZgatewayBT
+# ifndef BLEDecryptor
+# define BLEDecryptor true //true if decrypt encrypted PVVX or BTHome v2 service data
+# endif
+# ifndef JSON_BLE_AES_CUSTOM_KEYS
+# define JSON_BLE_AES_CUSTOM_KEYS 256 // 42 byte BLE Custom Key * 6 rounded up to 256.
+# endif
+# ifndef BLE_AES
+# define BLE_AES "00112233445566778899001122334455"
+# endif
+#endif
+
#define convertTemp_CtoF(c) ((c * 1.8) + 32)
#define convertTemp_FtoC(f) ((f - 32) * 5 / 9)
diff --git a/main/config_WebContent.h b/main/config_WebContent.h
index 9215d0d..eccf82f 100644
--- a/main/config_WebContent.h
+++ b/main/config_WebContent.h
@@ -62,7 +62,11 @@
#else
# define configure_6
#endif
-#define configure_7
+#ifdef BLEDecryptor
+# define configure_7 "
"
+#else
+# define configure_7
+#endif
#define configure_8
/*------------------- ----------------------*/
@@ -219,6 +223,15 @@ const char config_lora_body[] = body_header
""
"" body_footer_config_menu;
+#ifdef BLEDecryptor
+const char config_ble_body[] = body_header "" body_footer_config_menu;
+
+// Client side javascript validation of the Default AES Key is hex, and the custom keys are in the correct format. This pushes the theengs-bridge-v11 way of the file size, so reudcing it now and leaving it commented out
+//const char ble_script[] = "function bkv(){let e=document.getElementById('bk'),t=document.getElementById('bke'),l=e.value.trim();0===l.length||/^[A-Fa-f0-9]{32}$/.test(l)?(t.textContent='',e.style.color=''):(t.textContent='Invalid key',e.style.color='red')}function kpv(){let e=document.getElementById('kp'),t=document.getElementById('kpe'),l=e.value.split(/ /),n=/^[A-Fa-f0-9]{12}:[A-Fa-f0-9]{32}$/,o=l.map((e,t)=>({line:e,index:t})).filter(e=>!n.test(e.line));if(0===e.value.trim().length||0===o.length)t.textContent='',e.style.color='';else{let i=o.map(e=>e.index+1).join(', ');t.textContent=`Invalid format on line(s): ${i}`,e.style.color='red'}}";
+
+const char ble_script[] = "";
+#endif
+
const char footer[] = "