Next, add it as an approved sender in Amazon
- Open Amazon Settings and go to the Preferences tab
- Scroll down to Personal Document Settings
- Open the dropdown menu
- Click the Add a new approved email address button
- Paste in your Matter address
diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 62658b4..0000000 --- a/.dockerignore +++ /dev/null @@ -1,7 +0,0 @@ -.direnv -.github -.vscode -docs -hardware -nix -software diff --git a/.reuse/dep5 b/.reuse/dep5 index 5512039..0952f13 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -8,18 +8,13 @@ Copyright: (C) 2023 Curious Community Labs e. V. License: CERN-OHL-S-2.0 Files: - .github .vscode - .dockerignore .editorconfig .envrc .gitignore flake.* nix/* - Dockerfile - pyproject.toml okh.toml - mkdocs.yml software/* Copyright: (C) 2023 Curious Community Labs e. V. License: GPL-3.0-or-later diff --git a/README.md b/README.md index 15b47e2..5ce13bd 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,56 @@ -# IoT Platform +# Smart Energy Monitoring -## Docker +Smart Energy Monitoring is an open-source hardware project designed to empower individuals to monitor their energy consumption easily and efficiently. With the versatility of two different integrations - a DIY kit and a finished product - users can make informed decisions to manage and reduce their energy footprint. -First install DockerDesktop and `docker-compose`: +The project seamlessly integrates with the [IoT Prototyping Backend](https://code.curious.bio/curious.bio/iot-backend/) and serves as an exemplary application for the comprehensive integration of sensor systems, through the manipulation of data streams and visualization on a dashboard. -- https://www.docker.com/products/docker-desktop/ -- https://docs.docker.com/compose/install/ +## Features -Then you can export a path to mount as a volume and spin up the containers: +- Real-time energy monitoring +- Historical data logging +- MQTT Support +- Open-Source firmware -```sh -export DATA_DIR = /some/path/to/mount -docker-compose --file software/container/docker-compose.yml up -``` +## Integrations -### Mosquitto +### DIY Kit -```sh -mosquitto_sub -h localhost -t '#' -p 1883 -mosquitto_pub -h localhost -p 1883 -t '/' -m $(date --utc +%s) -``` +The DIY Kit includes an [ESP microcontroller](https://www.espressif.com/en/products/socs) and comes with appropriate measurement terminals. The firmware is open-source, based on the [Arduino framework](https://www.arduino.cc/reference/), allowing enthusiasts to extend or customize features according to their needs. -There is also a *very* usefuly tool to debug MQTT: [MQTT Explorer](https://github.com/thomasnordquist/MQTT-Explorer/), that is also available at [mqtt-explorer.com](https://mqtt-explorer.com/). +#### Hardware Requirements -### Node-RED +- [Bill of Material](./hardware/BOM.md) +- Soldering iron -NodeRed is running here: http://localhost:1880/ +### Shelly Plus Plug S -A simple introduction to Node-RED can be found - along with the nodes / the code - in [this repository, please have a look](./software/flow/README.md)! +For users looking for a ready-made solution, we support the [Shelly Plus Plug S](https://kb.shelly.cloud/knowledge-base/shelly-plus-plug-s) or any other ESP based Power Plug with measurement functions. We use the device with the open-source firmware [Tasmota](https://tasmota.github.io/), making integration into your existing smart home systems a breeze. The following page gives an overview of the [devices supported by Tasmota](https://templates.blakadder.com/plug.html). -### InfluxDB +## Safety Note -InfluxDb is running here: http://localhost:8086/ +> ⚠️ Handling High Voltage +> Working with electrical systems can be dangerous if not handled carefully. -### Grafana +Always make sure to: -You can login to Grafana: http://localhost:3000/login (admin:admin) +- Turn off the power supply before making any electrical connections. +- Use insulated tools. +- Work in a dry environment. +- If you are not confident or experienced in working with electricity, please contact a professional to assist you. -Have a look at the [HowTo in this repository](./software/dashboard/README.md). +## Installation +- [DIY Kit Installation](./docs/energy-monitor/README.md) +- [Shelly Plus Plug S](./docs/shelly-monitor/README.md) -## Hardware +## Contribution -We are using HelTec Automation Wirelsess Sticks ESP32 Dev-Boards. +Feel free to open an issue for bugs, feature requests, or questions. Contributions are welcome. -See the [documentation in this repository](./hardware/README.md). +## License -## Hardware sensors +This project follows the [REUSE Specification](https://reuse.software/spec/) and is licensed under the following: -* [Energy Monitor](./software/firmware/energy-monitor/README.md) -* [Plant Monitor](./software/firmware/plant-monitor/README.md) -* [Shelly Example](./software/firmware/shelly-monitor/README.md) \ No newline at end of file +- [Documentation: Creative Commons Attribution-ShareAlike 4.0 Licence](./LICENSES/CC-BY-SA-4.0.txt) +- [Hardware: CERN Open Hardware strongly reciprocal Licence](./LICENSES/CERN-OHL-S-2.0.txt) +- [Software: The GNU General Public License v3.0 Licence](./LICENSES/GPL-3.0-or-later.txt) diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index dea5927..0000000 Binary files a/docs/.DS_Store and /dev/null differ diff --git a/docs/datasheets/.gitkeep b/docs/datasheets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/documents/changelog.md b/docs/documents/changelog.md deleted file mode 100644 index 825c32f..0000000 --- a/docs/documents/changelog.md +++ /dev/null @@ -1 +0,0 @@ -# Changelog diff --git a/docs/documents/contribute/development.md b/docs/documents/contribute/development.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/documents/hardware/manufacturing.md b/docs/documents/hardware/manufacturing.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/documents/index.md b/docs/documents/index.md deleted file mode 100644 index 40ff1a0..0000000 --- a/docs/documents/index.md +++ /dev/null @@ -1 +0,0 @@ -# IoT platform for analyzing resource consumption and machine status diff --git a/docs/documents/software/.gitkeep b/docs/documents/software/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/documents/usage/getting-started.md b/docs/documents/usage/getting-started.md deleted file mode 100644 index e69de29..0000000 diff --git a/hardware/README.md b/docs/energy-monitor/HARDWARE.md similarity index 73% rename from hardware/README.md rename to docs/energy-monitor/HARDWARE.md index 751ff54..1786f33 100644 --- a/hardware/README.md +++ b/docs/energy-monitor/HARDWARE.md @@ -2,20 +2,21 @@ We are using HelTec Automation Wirelsess Sticks ESP32 Dev-Boards. -### PinOut +## PinOut -The PinOut of our version 3 modules can be found here: https://docs.heltec.org/en/node/esp32/dev-board/hardware_update_log.html#wifi-lora-32-hardware-update-logs +The PinOut of our version 3 modules can be found here: https://docs.heltec.org/en/node/esp32/dev-board/hardware_update_log.html#wifi-lora-32-hardware-update-logs -![PinOut](https://resource.heltec.cn/download/Wireless_Stick_V3/HTIT-WS_V3.png "PinOut") +![PinOut](../images/HTIT-WS_V3.png "PinOut") -### License +## License For some parts of the Heltec board you need a ["license"](https://docs.heltec.org/general/view_limited_technical_data.html#esp32-lora-series). -### USB-C +## USB-C + Our HelTec Automation Wirelsess Sticks ESP32 Dev-Boards already have USB-C. But they do not support Power Deliver (PD). If your computer tries to do PD, just plug a cheap USB hub between the board and your computer. -### Arduino IDE +## Arduino IDE HelTecs GitHub repo can be found here: https://github.com/HelTecAutomation/Heltec_ESP32 @@ -23,11 +24,11 @@ I had to install VCP Drivers, first: https://www.silabs.com/developers/usb-to-ua You can add their Board Manager to the boards managers URLs: https://github.com/HelTecAutomation/Heltec_ESP32/blob/master/library.json and find their libraries in the IDE (Sketch -> Include Library -> Manage Libraries... Search for "heltec esp32"). -> These boards are already *V3* boards, so be careful selecting the right board and port (VCP). +> These boards are already _V3_ boards, so be careful selecting the right board and port (VCP). -![Arduino IDE](docs/images/flash-with-arduino.png "select the right board and port") +![Arduino IDE](../images/flash-with-arduino.png "select the right board and port") -### Install esptool +## Install esptool Esptool is a Pyhton program to flash ESP32. As it's a Pyhton tool you can install it using `pip`: @@ -35,7 +36,7 @@ Esptool is a Pyhton program to flash ESP32. As it's a Pyhton tool you can instal pip install esptool ``` -### Find the port +## Find the port Usually you can find the used port using `esptool.py`: @@ -43,13 +44,12 @@ Usually you can find the used port using `esptool.py`: esptool.py write_flash_status --non-volatile 0 ``` -#### Using MicroPython +### Using MicroPython Download the firmware: https://micropython.org/download/ Flash it using `esptool`: https://micropython.org/download/GENERIC_S3/ - ```sh esptool.py --chip esp32s3 write_flash -z 0 ~/Desktop/GENERIC_S3-20220117-v1.18.bin -``` \ No newline at end of file +``` diff --git a/software/firmware/energy-monitor/README.md b/docs/energy-monitor/README.md similarity index 69% rename from software/firmware/energy-monitor/README.md rename to docs/energy-monitor/README.md index 12d4ea7..bcbc0bf 100644 --- a/software/firmware/energy-monitor/README.md +++ b/docs/energy-monitor/README.md @@ -1,6 +1,6 @@ # Energy Monitor -Our energy monitor is based on the openenergymonitor.org project (Licence GNU GPL V3). +Our energy monitor is based on the openenergymonitor.org project (Licence GNU GPL V3). It uses our HelTec Wireless Stick. This - of course - can be replaced by a cheaper ESP32 module. @@ -10,51 +10,46 @@ Power Measurement is done by a SCT013 clamp (100A:50mA). ### Used materials -* ESP32 module (e.g. Heltec Wireless Stick) -* 3 x SCT-013-100 (100 A), see: http://openenergymonitor.org/emon/node/156 -* 6 x 10 kOhm Resistors 1/4 W -* 1 x 22 Ohm Resistor 1/4 W (TODO: I am using a 47 Ohm Resistor to be replaced) -* 3 x 10 uF Elko 10 V -* 3 x 3,5 mm audio jack connector +- [Bill of Material](../../hardware/BOM.md) ### PinOut -![PinOut](https://resource.heltec.cn/download/Wireless_Stick_V3/HTIT-WS_V3.png "PinOut") +![PinOut](../images/HTIT-WS_V3.png "PinOut") We use A1, A2 and A3 because they are free (most ADCs are already used on the HelTec Board) -### Sensors +### Sensors The SCT-013 sensors are small current transformers (SCT). They have a ferromagnetic core that can be opened and in which we can enclose our conductor. This conductor is the primary winding and the secondary winding is fixed in the sensor and can have 2000 turns. This gives us a ratio of 1:2000 as an example. When AC current flows through the conductor, a magnetic flux is generated in the ferromagnetic core, which in turn generates an electric current in the secondary winding. -I could not meassure "small" power consumptions (like a LED lamp or a light stripe, as the magnetix flux in the ferromagnet core seems to be too small). +I could not meassure "small" power consumptions (like a LED lamp or a light stripe, as the magnetix flux in the ferromagnet core seems to be too small). -![clamp on wire](./docs/images/clamp1.jpeg "clamp on a wire") +![clamp on wire](../images/clamp1.jpeg "clamp on a wire") I was able to measure high loads (like a heater the can be switched between 1 kW and 2 kW). -![heater](./docs/images/example-heater.png "serial out of a heater") +![heater](../images/example-heater.png "serial out of a heater") -Make sure the clamp is *always positioned towards the consumer*, otherwise it does *not* work. There is a small arrow on the case. +Make sure the clamp is _always positioned towards the consumer_, otherwise it does _not_ work. There is a small arrow on the case. -![point the clamp](./docs/images/clamp2.jpeg "point the clamp") +![point the clamp](../images/clamp2.jpeg "point the clamp") > Attention: I could not measure any meaningful values on the "cable". I had to go to the wire. -![cable](./docs/images/clamp3.jpeg "use the clamp on the wire, not on the cable") +![cable](../images/clamp3.jpeg "use the clamp on the wire, not on the cable") ### Breadboard Let's start with a simple breadboard layout. -![Breadboard](./docs/images/breadboard.png "breakboard layout") -![Photo of breadboard](./docs/images/photo-breadboard.jpeg "photo of breadboard") +![Breadboard](../images/breadboard.png "breakboard layout") +![Photo of breadboard](../images/photo-breadboard.jpeg "photo of breadboard") To understand this, have a look at this plan: -![Plan](./docs/images/plan.png "plan") +![Plan](../images/plan.png "plan") R1 & R2 are a voltage divider that provides the 1.65 V source. We use 10 kΩ for mains powered monitors. If we want to run on batteries, we have to choose differnt ones (like 470 kΩ resistors to keep the power consumption to a minimum). @@ -62,15 +57,15 @@ Capacitor C1 has a low reactance - a few hundred ohms - and provides a path for R3 is the burden resistor. Ideal burden would be 19 Ω. As this is not a common value, you could choose 18 Ω or 22 Ω (I am still using a 47 Ω restistor, that has to be replaced). -See the Fritzing file for [details](./energy-monitor/energy-monitor.fzz). +See the Fritzing file for [details](./energy-monitor.fzz). ## Code ### Print to serial out -Start with a simple code that just prints the values. The code is quite simple, as we can use the existing *[EmonLib libary V1.1.0 by OpenEnergyMonitor](https://docs.openenergymonitor.org/electricity-monitoring/ct-sensors/)*. +Start with a simple code that just prints the values. The code is quite simple, as we can use the existing _[EmonLib libary V1.1.0 by OpenEnergyMonitor](https://docs.openenergymonitor.org/electricity-monitoring/ct-sensors/)_. -[Check out the small amount of code to print the values to serial out.](./01-energy-monitor-serial-out/) This piece of code is based on on Thomas Edlinger's code for [Edi's Tech Lab](https://www.edistechlab.com). +[Check out the small amount of code to print the values to serial out.](../../software/energy-monitor/01-energy-monitor-serial-out/) This piece of code is based on on Thomas Edlinger's code for [Edi's Tech Lab](https://www.edistechlab.com). The only interesting part is this line: @@ -82,7 +77,7 @@ The [calibration](https://docs.openenergymonitor.org/electricity-monitoring/ctac The code just prints the current power consumption to serial out: -``` +```txt 16:28:18.915 -> 2853.16 Watt - 12.41 Ampere 16:28:19.998 -> 2854.63 Watt - 12.41 Ampere 16:28:21.119 -> 2850.93 Watt - 12.40 Ampere @@ -90,19 +85,16 @@ The code just prints the current power consumption to serial out: 16:28:23.289 -> 400.62 Watt - 1.74 Ampere 16:28:24.367 -> 94.42 Watt - 0.41 Ampere ``` + ### Post to MQTT #### Boot up MQTT -First, boot your local server infrastructure: - -```sh -docker-compose --file software/container/docker-compose.yml up -``` +Now follow this documentation to set up [IoT Prototyping Backend](https://code.curious.bio/curious.bio/iot-backend). #### Credentials -To connect to your Wifi and access your MQTT server you have to add this to an `environment` [header file](./02-energy-monitor-mqtt/environment.h): +To connect to your Wifi and access your MQTT server you have to add this to an `environment` [header file](../../software/energy-monitor/02-energy-monitor-mqtt/environment.h): ```C // Replace with your network credentials @@ -136,16 +128,16 @@ Posting to MQTT is quite simple. After setting up Wifi and connection to the MQT client.publish(concat(mqttPrefix, "/ampere"), irmsArray); ``` -Have a look at the complete [example](./02-energy-monitor-mqtt/). +Have a look at the complete [example](../../software/energy-monitor/02-energy-monitor-mqtt/). ## Simulator -If you just need random inputs (without using the actual hardware), you can simply modify my short [shell script](./00-simulator/). +If you just need random inputs (without using the actual hardware), you can simply modify my short [shell script](../../software/energy-monitor/00-simulator/). ## Links -* A very comprehensive project to build an energy monitor can be found in the [ESP32 + ESPHome Open Source Energy Monitor project by Daniel BP](https://github.com/danpeig/ESP32EnergyMonitor). -* A nice (German) [video tutorial can be found at Eddie's Techlab](https://edistechlab.com/sct013-sensor-zum-wechselstrom-messen/). -* Have a look at the [complete documentation of the Open Energy Monitor project](https://docs.openenergymonitor.org/). -* There is also a German [example project](http://www.technik-fan.de/index.php/Open_Energy_Monitor_mit_dem_ESP32) (that currently cannot be reached over TLS, so be careful before clicking this link). -* MQTT and ESP32 is described in this article ["How to Connect ESP32 to MQTT Broker"](https://iotdesignpro.com/projects/how-to-connect-esp32-mqtt-broker). \ No newline at end of file +- A very comprehensive project to build an energy monitor can be found in the [ESP32 + ESPHome Open Source Energy Monitor project by Daniel BP](https://github.com/danpeig/ESP32EnergyMonitor). +- A nice (German) [video tutorial can be found at Eddie's Techlab](https://edistechlab.com/sct013-sensor-zum-wechselstrom-messen/). +- Have a look at the [complete documentation of the Open Energy Monitor project](https://docs.openenergymonitor.org/). +- There is also a German [example project](http://www.technik-fan.de/index.php/Open_Energy_Monitor_mit_dem_ESP32) (that currently cannot be reached over TLS, so be careful before clicking this link). +- MQTT and ESP32 is described in this article ["How to Connect ESP32 to MQTT Broker"](https://iotdesignpro.com/projects/how-to-connect-esp32-mqtt-broker). diff --git a/software/firmware/energy-monitor/energy-monitor/energy-monitor.fzz b/docs/energy-monitor/energy-monitor.fzz similarity index 100% rename from software/firmware/energy-monitor/energy-monitor/energy-monitor.fzz rename to docs/energy-monitor/energy-monitor.fzz diff --git a/docs/images/.gitkeep b/docs/images/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/images/HTIT-WS_V3.png b/docs/images/HTIT-WS_V3.png new file mode 100644 index 0000000..938682c Binary files /dev/null and b/docs/images/HTIT-WS_V3.png differ diff --git a/software/firmware/shelly-monitor/docs/images/blitzwolf.png b/docs/images/blitzwolf.png similarity index 100% rename from software/firmware/shelly-monitor/docs/images/blitzwolf.png rename to docs/images/blitzwolf.png diff --git a/docs/images/breadboard.png b/docs/images/breadboard.png new file mode 100644 index 0000000..ffe0d23 --- /dev/null +++ b/docs/images/breadboard.png @@ -0,0 +1,569 @@ + + +
+ +=b[n+1]?b[n+1]-1:b[n-1],d=c-(n-C)-y;const l=c;for(;c>e&&d>i&&this.ElementsAreEqual(c,d);)c--,d--;if(b[n]=c,S&&Math.abs(n-v)<=x&&c<=_[n])return r[0]=c,s[0]=d,l>=_[n]&&x<=1448?this.WALKTRACE(v,u,h,w,C,g,p,y,_,b,c,t,r,d,o,s,S,a):null}if(x<=1447){let e=new Int32Array(h-u+2);e[0]=v-u+1,l.Copy2(_,u,e,1,h-u+1),this.m_forwardHistory.push(e),e=new Int32Array(p-g+2),e[0]=C-g+1,l.Copy2(b,g,e,1,p-g+1),this.m_reverseHistory.push(e)}}return this.WALKTRACE(v,u,h,w,C,g,p,y,_,b,c,t,r,d,o,s,S,a)}PrettifyChanges(e){for(let t=0;t "+e+"1;n--){const o=e[n]+i,r=t[t.length-1];r&&r.end===o?r.end=o+1:t.push({start:o,end:o+1})}return t}const I=128;function T(){const e=[],t=[];for(let e=0;e<=I;e++)t[e]=0;for(let i=0;i<=I;i++)e.push(t.slice(0));return e}function A(e){const t=[];for(let i=0;i<=e;i++)t[i]=0;return t}const R=A(256),M=A(256),O=T(),P=T(),F=T();function B(e,t){if(t<0||t>=e.length)return!1;const i=e.codePointAt(t);switch(i){case 95:case 45:case 46:case 32:case 47:case 92:case 39:case 34:case 58:case 36:case 60:case 40:case 91:return!0;case void 0:return!1;default:return!!o.C8(i)}}function W(e,t){if(t<0||t>=e.length)return!1;switch(e.charCodeAt(t)){case 32:case 9:return!0;default:return!1}}function V(e,t,i){return t[e]!==i[e]}var H;function z(e,t,i,n,o,r,s){const a=e.length>I?I:e.length,l=n.length>I?I:n.length;if(i>=a||r>=l||a-i>l-r)return;if(!function(e,t,i,n,o,r,s=!1){for(;t=i&&a>=n;)o[s]===r[a]&&(M[s]=a,s--),a--}(a,l,i,r,t,o);let c=1,d=1,u=i,h=r;const g=[!1];for(c=1,u=i;us,b=_?P[c][d-1]+(O[c][d-1]>0?-5:0):0,v=h>s+1&&O[c][d-1]>0,C=v?P[c][d-2]+(O[c][d-2]>0?-5:0):0;if(v&&(!_||C>=b)&&(!m||C>=f))P[c][d]=C,F[c][d]=3,O[c][d]=0;else if(_&&(!m||b>=f))P[c][d]=b,F[c][d]=2,O[c][d]=0;else{if(!m)throw new Error("not possible");P[c][d]=f,F[c][d]=1,O[c][d]=O[c-1][d-1]+1}}}if(!g[0]&&!s)return;c--,d--;const p=[P[c][d],r];let m=0,f=0;for(;c>=1;){let e=d;do{const t=F[c][e];if(3===t)e-=2;else{if(2!==t)break;e-=1}}while(e>=1);m>1&&t[i+c-1]===o[r+d-1]&&!V(e+r-1,n,o)&&m+1>O[c][e]&&(e=d),e===d?m++:m=1,f||(f=e),c--,d=e-1,p.push(d)}l===a&&(p[0]+=2);const _=f-a;return p[0]-=_,p}function $(e,t,i,n,o,r,s,a,l,c,d){if(t[i]!==r[s])return Number.MIN_SAFE_INTEGER;let u=1,h=!1;return s===i-n?u=e[i]===o[s]?7:5:!V(s,o,r)||0!==s&&V(s-1,o,r)?!B(r,s)||0!==s&&B(r,s-1)?(B(r,s-1)||W(r,s-1))&&(u=5,h=!0):u=5:(u=e[i]===o[s]?7:5,h=!0),u>1&&i===n&&(d[0]=!0),h||(h=V(s,o,r)||B(r,s-1)||W(r,s-1)),i===n?s>l&&(u-=h?3:5):u+=c?h?2:0:h?0:1,s+1===a&&(u-=h?3:5),u}function U(e,t,i,n,o,r,s){return function(e,t,i,n,o,r,s,a){let l=z(e,t,i,n,o,r,a);if(e.length>=3){const t=Math.min(7,e.length-1);for(let s=i+1;s
\n":"'+(i?e:u(e,!0))+"
\n"},i.blockquote=function(e){return""+(i?e:u(e,!0))+"
\n"+e+"
\n"},i.html=function(e){return e},i.heading=function(e,t,i,n){return this.options.headerIds?"
\n":"
\n"},i.list=function(e,t,i){var n=t?"ol":"ul";return"<"+n+(t&&1!==i?' start="'+i+'"':"")+">\n"+e+""+n+">\n"},i.listitem=function(e){return"\n\n"+e+"\n"+t+"
\n"},i.tablerow=function(e){return"\n"+e+" \n"},i.tablecell=function(e,t){var i=t.header?"th":"td";return(t.align?"<"+i+' align="'+t.align+'">':"<"+i+">")+e+""+i+">\n"},i.strong=function(e){return""+e+""},i.em=function(e){return""+e+""},i.codespan=function(e){return""+e+"
"},i.br=function(){return this.options.xhtml?"
":"
"},i.del=function(e){return""+e+""},i.link=function(e,t,i){if(null===(e=b(this.options.sanitize,this.options.baseUrl,e)))return i;var n='"+i+""},i.image=function(e,t,i){if(null===(e=b(this.options.sanitize,this.options.baseUrl,e)))return i;var n='":">")},i.text=function(e){return e},t}(),F=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,i){return""+i},t.image=function(e,t,i){return""+i},t.br=function(){return""},e}(),B=function(){function e(){this.seen={}}var t=e.prototype;return t.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},t.getNextSafeSlug=function(e,t){var i=e,n=0;if(this.seen.hasOwnProperty(i)){n=this.seen[e];do{i=e+"-"+ ++n}while(this.seen.hasOwnProperty(i))}return t||(this.seen[e]=n,this.seen[i]=0),i},t.slug=function(e,t){void 0===t&&(t={});var i=this.serialize(e);return this.getNextSafeSlug(i,t.dryrun)},e}(),W=function(){function t(t){this.options=t||e.defaults,this.options.renderer=this.options.renderer||new P,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new F,this.slugger=new B}t.parse=function(e,i){return new t(i).parse(e)},t.parseInline=function(e,i){return new t(i).parseInline(e)};var i=t.prototype;return i.parse=function(e,t){void 0===t&&(t=!0);var i,n,o,r,s,a,l,c,d,u,h,p,m,f,_,b,v,C,w,y="",S=e.length;for(i=0;i0&&"paragraph"===_.tokens[0].type?(_.tokens[0].text=C+" "+_.tokens[0].text,_.tokens[0].tokens&&_.tokens[0].tokens.length>0&&"text"===_.tokens[0].tokens[0].type&&(_.tokens[0].tokens[0].text=C+" "+_.tokens[0].tokens[0].text)):_.tokens.unshift({type:"text",text:C}):f+=C),f+=this.parse(_.tokens,m),d+=this.renderer.listitem(f,v,b);y+=this.renderer.list(d,h,p);continue;case"html":y+=this.renderer.html(u.text);continue;case"paragraph":y+=this.renderer.paragraph(this.parseInline(u.tokens));continue;case"text":for(d=u.tokens?this.parseInline(u.tokens):u.text;i+1An error occurred:
"+u(e.message+"",!0)+"";throw e}}V.options=V.setOptions=function(t){var i;return x(V.defaults,t),i=V.defaults,e.defaults=i,V},V.getDefaults=o,V.defaults=e.defaults,V.use=function(){for(var e=arguments.length,t=new Array(e),i=0;i
"+u(e.message+"",!0)+"";throw e}},V.Parser=W,V.parser=W.parse,V.Renderer=P,V.TextRenderer=F,V.Lexer=O,V.lexer=O.lex,V.Tokenizer=I,V.Slugger=B,V.parse=V;var H=V.options,z=V.setOptions,$=V.use,U=V.walkTokens,j=V.parseInline,K=V,q=W.parse,G=O.lex;e.Lexer=O,e.Parser=W,e.Renderer=P,e.Slugger=B,e.TextRenderer=F,e.Tokenizer=I,e.getDefaults=o,e.lexer=G,e.marked=V,e.options=H,e.parse=K,e.parseInline=j,e.parser=q,e.setOptions=z,e.use=$,e.walkTokens=U,Object.defineProperty(e,"__esModule",{value:!0})},"object"==typeof exports?i(exports):e.amd?e(0,i):i((t="undefined"!=typeof globalThis?globalThis:t||self).marked={})}();var me=pe||exports,fe=i(60491),_e=i(9734),be=i(90584),ve=i(10804),Ce=i(18039),we=i(39675);function ye(e,t){return/^\w[\w\d+.-]*:/.test(t)?t:e.path.endsWith("/")?(0,ve.i3)(e,t).toString():(0,ve.i3)((0,ve.XX)(e),t).toString()}function Se(e,t){const{config:i,allowedSchemes:n}=function(e){const t=[_e.lg.http,_e.lg.https,_e.lg.mailto,_e.lg.data,_e.lg.file,_e.lg.vscodeFileResource,_e.lg.vscodeRemote,_e.lg.vscodeRemoteResource];return e.isTrusted&&t.push(_e.lg.command),{config:{ALLOWED_TAGS:["ul","li","p","b","i","code","blockquote","ol","h1","h2","h3","h4","h5","h6","hr","em","pre","table","thead","tbody","tr","th","td","div","del","a","strong","br","img","span"],ALLOWED_ATTR:["href","data-href","target","title","src","alt","class","style","data-code","width","height","align"],ALLOW_UNKNOWN_PROTOCOLS:!0},allowedSchemes:t}}(e);ee("uponSanitizeAttribute",((e,t)=>{if("style"!==t.attrName&&"class"!==t.attrName);else{if("SPAN"===e.tagName){if("style"===t.attrName)return void(t.keepAttr=/^(color\:#[0-9a-fA-F]+;)?(background-color\:#[0-9a-fA-F]+;)?$/.test(t.attrValue));if("class"===t.attrName)return void(t.keepAttr=/^codicon codicon-[a-z\-]+( codicon-modifier-[a-z\-]+)?$/.test(t.attrValue))}t.keepAttr=!1}}));const o=document.createElement("a");ee("afterSanitizeAttributes",(e=>{for(const t of["href","src"])e.hasAttribute(t)&&(o.href=e.getAttribute(t),n.includes(o.protocol.replace(/:$/,""))||e.removeAttribute(t))}));try{return J(t,Object.assign(Object.assign({},i),{RETURN_TRUSTED_TYPE:!0}))}finally{te("uponSanitizeAttribute"),te("afterSanitizeAttributes")}}var xe,ke=i(82523),Le=i(10940),Ee=i(54571),Ne=i(18226),De=i(11233),Ie=function(e,t){return function(i,n){t(i,n,e)}};let Te=class e{constructor(e,t,i){this._options=e,this._languageService=t,this._openerService=i,this._onDidRenderAsync=new ce.Q5,this.onDidRenderAsync=this._onDidRenderAsync.event}dispose(){this._onDidRenderAsync.dispose()}render(e,t,i){if(!e)return{element:document.createElement("span"),dispose:()=>{}};const o=new ge.SL,r=o.add(function(e,t={},i={}){var o;const r=new ge.SL;let s=!1;const a=r.add(new ae.A),l=(0,ne.az)(t),c=function(t){let i;try{i=(0,fe.Q)(decodeURIComponent(t))}catch(e){}return i?(i=(0,be.rs)(i,(t=>e.uris&&e.uris[t]?we.o.revive(e.uris[t]):void 0)),encodeURIComponent(JSON.stringify(i))):t},d=function(t,i){const n=e.uris&&e.uris[t];let o=we.o.revive(n);return i?t.startsWith(_e.lg.data+":")?t:(o||(o=we.o.parse(t)),_e.Gi.asBrowserUri(o).toString(!0)):o?we.o.parse(t).toString()===o.toString()?t:(o.query&&(o=o.with({query:c(o.query)})),o.toString()):t};let u;const h=new Promise((e=>u=e)),g=new me.Renderer;if(g.image=(e,t,i)=>{let n=[],o=[];return e&&(({href:e,dimensions:n}=(0,de.v1)(e)),o.push(`src="${e}"`)),i&&o.push(`alt="${i}"`),t&&o.push(`title="${t}"`),n.length&&(o=o.concat(n)),""},g.link=(t,i,n)=>"string"!=typeof t?"":(t===n&&(n=(0,de.oR)(n)),t=d(t,!1),e.baseUri&&(t=ye(we.o.from(e.baseUri),t)),i="string"==typeof i?(0,de.oR)(i):"",!(t=(0,de.oR)(t))||/^data:|javascript:/i.test(t)||/^command:/i.test(t)&&!e.isTrusted||/^command:(\/\/\/)?_workbench\.downloadResource/i.test(t)?n:`/g,">").replace(/"/g,""").replace(/'/g,"'")}" title="${i||t}">${n}`),g.paragraph=e=>`
${e}
`,t.codeBlockRenderer&&(g.code=(e,i)=>{const o=t.codeBlockRenderer(null!=i?i:"",e),r=he.a.nextId();return(0,se.eP)(Promise.all([o,h]),a.token).then((e=>{var i;if(!s&&e){const o=l.querySelector(`div[data-code="${r}"]`);o&&n.mc(o,e[0]),null===(i=t.asyncRenderCallback)||void 0===i||i.call(t)}})).catch((()=>{})),`