{"id":7166,"date":"2024-07-28T07:41:01","date_gmt":"2024-07-28T07:41:01","guid":{"rendered":"http:\/\/172.30.70.55\/?p=7166"},"modified":"2024-08-23T21:08:40","modified_gmt":"2024-08-23T21:08:40","slug":"apc-pdu-snmp-to-mqtt","status":"publish","type":"post","link":"https:\/\/phixd.us\/?p=7166","title":{"rendered":"APC PDU &#8211; SNMP to MQTT"},"content":{"rendered":"\n<h2 class=\"wp-block-heading has-medium-font-size\"><strong>Guide for SNMP and MQTT Integration Script<\/strong><\/h2>\n\n\n\n<p class=\"has-medium-font-size\">This is a script I developed to retrieve status information from my APC PDU. While there may be other solutions available, I chose to create my own and integrate it with MQTT discovery so it could seamlessly integrate with Home Assistant. This setup has worked reliably for me for months. I&#8217;m always open to suggestions for improvement and hope you find it useful.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>Prerequisites<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Python Environment<\/strong>: Ensure you have Python installed on your system.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Python Packages<\/strong>: Install the required packages using&#8230;<\/li>\n<\/ol>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"pip install paho-mqtt==1.6.1\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">pip<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">paho<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">==<\/span><span style=\"color: #B5CEA8\">1.6<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #B5CEA8\">1<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>SNMP Enabled Device<\/strong>: You need a device with SNMP enabled.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>MQTT Broker<\/strong>: Ensure you have access to an MQTT broker.<\/li>\n<\/ol>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\"><strong>Docker Option<\/strong><\/h4>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\"><strong>1. Create the Python Script<\/strong><\/h4>\n\n\n\n<p class=\"has-medium-font-size\">Save your Python script as <code>apc2mqtt.py<\/code> in the your preferred directory in this example \/opt\/scripts.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\"><strong>2. Create a Dockerfile<\/strong><\/h4>\n\n\n\n<p class=\"has-medium-font-size\">Create a <code>Dockerfile<\/code> in the same directory where your <code>apc2mqtt.py<\/code> script is located:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"DockerfileCopy code# Use the official Python image as a base\nFROM python:3.9-slim\n\n# Set the working directory\nWORKDIR \/opt\/scripts\n\n# Copy the requirements file\nCOPY requirements.txt .\n\n# Install the required Python packages\nRUN pip install --no-cache-dir -r requirements.txt\n\n# Copy the Python script\nCOPY apc2mqtt.py .\n\n# Command to run the script\nCMD [&quot;python&quot;, &quot;apc2mqtt.py&quot;]\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">DockerfileCopy<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">code<\/span><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Use<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">official<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Python<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">image<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">base<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">FROM<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C8C8C8\">python<\/span><span style=\"color: #D4D4D4\">:<\/span><span style=\"color: #B5CEA8\">3.9<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">slim<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Set<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">working<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">directory<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">WORKDIR<\/span><span style=\"color: #D4D4D4\"> \/<\/span><span style=\"color: #9CDCFE\">opt<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">scripts<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Copy<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">requirements<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">file<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">COPY<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">requirements<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">txt<\/span><span style=\"color: #D4D4D4\"> .<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Install<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">required<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Python<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">packages<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">RUN<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">pip<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> --<\/span><span style=\"color: #9CDCFE\">no<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">cache<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">dir<\/span><span style=\"color: #D4D4D4\"> -<\/span><span style=\"color: #9CDCFE\">r<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">requirements<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">txt<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Copy<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Python<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">script<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">COPY<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">apc2mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">py<\/span><span style=\"color: #D4D4D4\"> .<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Command<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">run<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">script<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4FC1FF\">CMD<\/span><span style=\"color: #D4D4D4\"> [<\/span><span style=\"color: #CE9178\">&quot;python&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;apc2mqtt.py&quot;<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\">3. Create a Requirements File<\/h4>\n\n\n\n<p class=\"has-medium-font-size\">Create a <code>requirements.txt<\/code> file in the same directory to specify the dependencies:<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"paho-mqtt==1.6.1\npysnmp\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">paho<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">==<\/span><span style=\"color: #B5CEA8\">1.6<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #B5CEA8\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">pysnmp<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\">4. Create a Docker Compose File<\/h4>\n\n\n\n<p class=\"has-medium-font-size\">Create a <code>docker-compose.yml<\/code> file in the same directory:<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"codeversion: &quot;3&quot;\nservices:\n  apc2mqtt-servers:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    volumes:\n      - \/opt\/scripts:\/opt\/scripts\n    command: python \/opt\/scripts\/apc2mqtt.py\n    restart: always\n    networks:\n      - apc2mqtt-net\n\nnetworks:\n  apc2mqtt-net:\n    driver: bridge\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C8C8C8\">codeversion<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;3&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C8C8C8\">services<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #9CDCFE\">apc2mqtt<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #C8C8C8\">servers<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">build<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C8C8C8\">context<\/span><span style=\"color: #D4D4D4\">: .<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C8C8C8\">dockerfile<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">Dockerfile<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">volumes<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      - \/<\/span><span style=\"color: #9CDCFE\">opt<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #C8C8C8\">scripts<\/span><span style=\"color: #D4D4D4\">:\/<\/span><span style=\"color: #9CDCFE\">opt<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">scripts<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">command<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">python<\/span><span style=\"color: #D4D4D4\"> \/<\/span><span style=\"color: #9CDCFE\">opt<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">scripts<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">apc2mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">py<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">restart<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">always<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">networks<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      - <\/span><span style=\"color: #9CDCFE\">apc2mqtt<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">net<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C8C8C8\">networks<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #9CDCFE\">apc2mqtt<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #C8C8C8\">net<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C8C8C8\">driver<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">bridge<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4 class=\"wp-block-heading has-medium-font-size\"><strong>5. Build and Run the Docker Container<\/strong><\/h4>\n\n\n\n<p class=\"has-medium-font-size\">Navigate to the directory containing your <code>Dockerfile<\/code> and <code>docker-compose.yml<\/code> and run the following commands:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Build the Docker image:<\/strong><\/li>\n<\/ol>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"docker-compose build\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">docker<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">compose<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">build<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Run the Docker container:<\/strong><\/li>\n<\/ol>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"docker-compose up -d\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">docker<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">compose<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">up<\/span><span style=\"color: #D4D4D4\"> -<\/span><span style=\"color: #9CDCFE\">d<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div style=\"height:60px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Configuration<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>SNMP Configuration:<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>snmp_ip_address<\/code>: The IP address of the SNMP-enabled device.<\/li>\n\n\n\n<li><code>community_string<\/code>: The SNMP community string (usually &#8216;public&#8217;).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>MQTT Configuration:<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>mqtt_broker<\/code>: The IP address of your MQTT broker.<\/li>\n\n\n\n<li><code>mqtt_port<\/code>: The port your MQTT broker is listening on (default is 1883).<\/li>\n\n\n\n<li><code>mqtt_user<\/code>: MQTT username.<\/li>\n\n\n\n<li><code>mqtt_password<\/code>: MQTT password.<\/li>\n\n\n\n<li><code>device_id<\/code>: A unique identifier for your device (e.g., &#8216;servers&#8217;).<\/li>\n\n\n\n<li><code>debug_mode<\/code>: Set to <code>True<\/code> for verbose debug logging.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Polling Interval:<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>sleep_duration<\/code>: Time in seconds between each status poll and publish cycle.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Integrating with Home Assistant<\/strong><\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\n<p class=\"has-medium-font-size\">This integrates with Home Assistant using MQTT discovery. When the script runs, it publishes discovery messages to the MQTT broker. Home Assistant listens for these messages and automatically configures the corresponding entitier. <\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>Handling Multiple PDUs<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size\">If you have multiple PDUs, you can change the <code>device_id<\/code> in the script configuration to ensure each PDU has a unique identifier. This allows Home Assistant to handle multiple instances without conflicts.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"device_id = 'it_equitment'\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;it_equitment&#39;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>Supported PDUs<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size\">This script has only been tested with an APC PDU model AP7900. However, it should be straightforward to update the SNMP OIDs in the script to support other models or brands of PDUs.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div>\n<\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Script:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from pysnmp.hlapi import getCmd, setCmd, SnmpEngine, CommunityData, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity, Integer32\nimport paho.mqtt.client as mqtt\nimport paho.mqtt.publish as publish\nimport json\nimport time\n\n# Configuration\nsnmp_ip_address = '192.168.1.1'\ncommunity_string = 'public'\nmqtt_broker = '192.168.1.2'\nmqtt_port = 1883\nmqtt_user = 'user'\nmqtt_password = 'password'\ndevice_id = 'it_equitment'\ndebug_mode = False\n\nglobal_port_names = {}\n\nsleep_duration = 25\n\ndef debug_print(message):\n    if debug_mode:\n        print(message)\n\ndef fetch_snmp_data(oid):\n    errorIndication, errorStatus, errorIndex, varBinds = next(\n        getCmd(SnmpEngine(),\n               CommunityData(community_string, mpModel=0),\n               UdpTransportTarget((snmp_ip_address, 161)),\n               ContextData(),\n               ObjectType(ObjectIdentity(oid)))\n    )\n    if errorIndication:\n        debug_print(f&quot;SNMP Fetch Error: {errorIndication}&quot;)\n        return None\n    elif errorStatus:\n        debug_print(f&quot;SNMP Fetch Error Status: {errorStatus.prettyPrint()}&quot;)\n        return None\n    else:\n        for varBind in varBinds:\n            return varBind[1].prettyPrint()\n\ndef control_port(snmp_ip_address, port_num, state, client):\n    oid_base = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4'\n    full_oid = f&quot;{oid_base}.{port_num}&quot;  \n    state_value = 1 if state == 1 else 2\n    \n    # Log the action being attempted\n    debug_message = f&quot;Preparing to send SNMP set command for port {port_num} to {'on' if state == 1 else 'off'} (value: {state_value}). OID: {full_oid}&quot;\n    publish_debug(client, debug_message)\n    \n    try:\n        errorIndication, errorStatus, errorIndex, varBinds = next(\n            setCmd(SnmpEngine(),\n                   CommunityData('private', mpModel=0),\n                   UdpTransportTarget((snmp_ip_address, 161)),\n                   ContextData(),\n                   ObjectType(ObjectIdentity(full_oid), Integer32(state_value)))\n        )\n        \n        if errorIndication:\n            publish_debug(client, f&quot;SNMP Error: {errorIndication} for port {port_num}&quot;)\n            return\n        elif errorStatus:\n            publish_debug(client, f&quot;SNMP Error: {errorStatus.prettyPrint()} for port {port_num} when attempting to set to {'on' if state == 1 else 'off'}&quot;)\n            return\n        else:\n            state_str = 'on' if state == 1 else 'off'\n            client.publish(f&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/state&quot;, state_str)\n            publish_debug(client, f&quot;SNMP set command sent successfully for port {port_num}, updated MQTT with state '{state_str}'.&quot;)\n    except Exception as e:\n        publish_debug(client, f&quot;Exception sending SNMP set command for port {port_num}: {e}&quot;)\n\n\n\ndef format_mac_address(raw_mac):\n    if raw_mac.lower().startswith(&quot;0x&quot;):\n        raw_mac = raw_mac[2:]\n    raw_mac = raw_mac.upper()\n    formatted_mac = &quot;:&quot;.join(raw_mac[i:i+2] for i in range(0, len(raw_mac), 2))\n    return formatted_mac\n\ndef publish_status(client, port_num=None):\n    global global_serial, global_model, global_mac, global_port_names\n\n    global_serial = 'Unknown or Unable to Connect'\n    global_model = 'Unknown or Unable to Connect'\n    global_mac = 'Unknown or Unable to Connect'\n\n    serial_temp = fetch_snmp_data('.1.3.6.1.4.1.318.1.1.4.1.5.0')\n    model_temp = fetch_snmp_data('.1.3.6.1.4.1.318.1.1.4.1.4.0')\n    raw_mac = fetch_snmp_data('.1.3.6.1.2.1.2.2.1.6.2')\n\n    if serial_temp is not None:\n        global_serial = serial_temp\n    if model_temp is not None:\n        global_model = model_temp\n    if raw_mac is not None:\n        global_mac = format_mac_address(raw_mac)\n\n    system_uptime_oid = '.1.3.6.1.2.1.1.3.0'\n    system_uptime_ticks = fetch_snmp_data(system_uptime_oid)\n    if system_uptime_ticks is not None:\n        system_uptime_readable = convert_time_ticks_to_readable_format(system_uptime_ticks)\n        client.publish(f&quot;apc_pdu_{device_id}\/status\/uptime&quot;, system_uptime_readable)\n    else:\n        client.publish(f&quot;apc_pdu_{device_id}\/status\/uptime&quot;, &quot;Uptime fetch failed&quot;)\n\n    port_range = range(1, 9) if port_num is None else [port_num]\n\n    for port_num in port_range:\n        try:\n            name_oid = f'1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.{port_num}'\n            state_oid = f'1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.{port_num}'\n            port_name = fetch_snmp_data(name_oid) or &quot;Unknown Port Name&quot;\n            port_state = 'on' if fetch_snmp_data(state_oid) == '1' else 'off'\n            global_port_names[port_num] = port_name\n\n            client.publish(f&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/name&quot;, port_name)\n            client.publish(f&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/state&quot;, port_state)\n        except Exception as e:\n            print(f&quot;Error updating port {port_num}: {e}&quot;)\n\n    # Publish global device information\n    client.publish(f&quot;apc_pdu_{device_id}\/status\/serial&quot;, global_serial)\n    client.publish(f&quot;apc_pdu_{device_id}\/status\/model&quot;, global_model)\n    client.publish(f&quot;apc_pdu_{device_id}\/status\/mac&quot;, global_mac)\n    client.publish(f&quot;apc_pdu_{device_id}\/status\/identifier&quot;, device_id)\n    \n    # Ensure discovery messages are published even if there's an issue\n    try:\n        publish_discovery_messages(client)\n    except Exception as e:\n        debug_print(f&quot;Error publishing discovery messages: {e}&quot;)\n\ndef convert_time_ticks_to_readable_format(time_ticks):\n    total_seconds = int(time_ticks) \/ 100  # Convert TimeTicks to seconds\n\n    days = total_seconds \/\/ (24 * 3600)\n    total_seconds = total_seconds % (24 * 3600)\n\n    hours = total_seconds \/\/ 3600\n    total_seconds %= 3600\n\n    minutes = total_seconds \/\/ 60\n\n    return f&quot;{int(days)} days, {int(hours)} hours, {int(minutes)} minutes&quot;\n\n\ndef publish_debug(client, message):\n    if debug_mode:\n        debug_topic = f&quot;apc_pdu_{device_id}\/debug\/logs&quot;\n        client.publish(debug_topic, message)\n\ndef on_connect(client, userdata, flags, rc):\n    publish_debug(client, f&quot;Connected with result code {rc}&quot;)\n    for port_num in range(1, 9):\n        topic = f&quot;apc_pdu_{device_id}\/control\/ports\/{port_num}&quot;\n        client.subscribe(topic)\n        publish_debug(client, f&quot;Subscribing to topic: {topic}&quot;)\n\n\ndef on_message(client, userdata, msg):\n    message = msg.payload.decode('utf-8')\n    topic_parts = msg.topic.split('\/')\n    if len(topic_parts) != 4:\n        publish_debug(client, f&quot;Received message on unexpected topic: {msg.topic}&quot;)\n        return\n\n    expected_prefix = f'apc_pdu_{device_id}'\n    received_prefix = topic_parts[0]\n\n    # Debug output for diagnostic purposes\n    publish_debug(client, f&quot;Diagnostic: Expecting prefix '{expected_prefix}', received '{received_prefix}'&quot;)\n\n    if received_prefix == expected_prefix and topic_parts[1] == 'control' and topic_parts[2] == 'ports':\n        try:\n            port_num = int(topic_parts[3])\n            state = 1 if message.lower() == 'on' else 0  # Assuming '0' is the correct state for 'off'\n            control_port(snmp_ip_address, port_num, state, client)\n        except ValueError as e:\n            publish_debug(client, f&quot;Error processing command for topic {msg.topic}: {e}&quot;)\n    else:\n        publish_debug(client, f&quot;Received message does not match expected structure: {msg.topic}&quot;)\n\n\n\ndef publish_discovery_messages(client):\n    global global_serial, global_model, global_mac, global_port_names\n\n    # Publishing for each port\n    for port_num in range(1, 9):\n        port_name = global_port_names.get(port_num, f&quot;Port {port_num}&quot;)\n        device_name = f&quot;Port {port_num} - {port_name}&quot;\n\n        port_discovery_message = {\n            &quot;name&quot;: device_name,\n            &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/state&quot;,\n            &quot;command_topic&quot;: f&quot;apc_pdu_{device_id}\/control\/ports\/{port_num}&quot;,\n            &quot;unique_id&quot;: f&quot;apc_pdu_port_{port_num}_{global_serial}_{device_id}&quot;,\n            &quot;icon&quot;: &quot;mdi:power-plug&quot;,\n            &quot;device&quot;: {\n                &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n                &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,\n                &quot;model&quot;: global_model,\n                &quot;manufacturer&quot;: &quot;APC&quot;,\n            },\n            &quot;payload_on&quot;: &quot;on&quot;,\n            &quot;payload_off&quot;: &quot;off&quot;,\n            &quot;value_template&quot;: &quot;{{ value if value == 'on' else 'off' }}&quot;\n        }\n\n        publish.single(\n            f&quot;homeassistant\/switch\/apc_pdu_{device_id}\/port_{port_num}\/config&quot;,\n            payload=json.dumps(port_discovery_message),\n            hostname=mqtt_broker,\n            port=mqtt_port,\n            auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n            retain=True,\n        )\n\n    # Serial Number Discovery Message\n    serial_discovery_message = {\n        &quot;name&quot;: &quot;Serial Number&quot;,\n        &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/serial&quot;,\n        &quot;unique_id&quot;: f&quot;apc_pdu_serial_{global_serial}_{device_id}&quot;,\n        &quot;icon&quot;: &quot;mdi:alphabetical&quot;,\n        &quot;device&quot;: {\n            &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n            &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,\n            &quot;model&quot;: global_model,\n            &quot;manufacturer&quot;: &quot;APC&quot;,\n        },\n    }\n    publish.single(\n        f&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/serial\/config&quot;,\n        payload=json.dumps(serial_discovery_message),\n        hostname=mqtt_broker,\n        port=mqtt_port,\n        auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n        retain=True,\n    )\n\n    # Model Discovery Message\n    model_discovery_message = {\n        &quot;name&quot;: &quot;Model&quot;,\n        &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/model&quot;,\n        &quot;unique_id&quot;: f&quot;apc_pdu_model_{global_serial}_{device_id}&quot;,\n        &quot;icon&quot;: &quot;mdi:information-outline&quot;,\n        &quot;device&quot;: {\n            &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n            &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,  \n            &quot;model&quot;: global_model,\n            &quot;manufacturer&quot;: &quot;APC&quot;,\n        },\n    }\n    publish.single(\n        f&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/model\/config&quot;,\n        payload=json.dumps(model_discovery_message),\n        hostname=mqtt_broker,\n        port=mqtt_port,\n        auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n        retain=True,\n    )\n\n    # MAC Address Discovery Message\n    mac_discovery_message = {\n        &quot;name&quot;: &quot;MAC Address&quot;,\n        &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/mac&quot;,\n        &quot;unique_id&quot;: f&quot;apc_pdu_mac_{global_serial}_{device_id}&quot;,\n        &quot;icon&quot;: &quot;mdi:ethernet&quot;,\n        &quot;device&quot;: {\n            &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n            &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,\n            &quot;model&quot;: global_model,\n            &quot;manufacturer&quot;: &quot;APC&quot;,\n        },\n        &quot;value_template&quot;: &quot;{{ value }}&quot;\n    }\n    publish.single(\n        f&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/mac\/config&quot;,\n        payload=json.dumps(mac_discovery_message),\n        hostname=mqtt_broker,\n        port=mqtt_port,\n        auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n        retain=True,\n    )\n\n    # Identifier Discovery Message\n    identifier_discovery_message = {\n        &quot;name&quot;: &quot;Identifier&quot;,\n        &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/identifier&quot;,\n        &quot;unique_id&quot;: f&quot;apc_pdu_identifier_{global_serial}_{device_id}&quot;,\n        &quot;icon&quot;: &quot;mdi:identifier&quot;,\n        &quot;device&quot;: {\n            &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n            &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,\n            &quot;model&quot;: global_model,\n            &quot;manufacturer&quot;: &quot;APC&quot;,\n        },\n    }\n\n    # Publishing the Identifier Discovery Message\n    publish.single(\n        f&quot;homeassistant\/sensor\/{device_id}\/identifier\/config&quot;,\n        payload=json.dumps(identifier_discovery_message),\n        hostname=mqtt_broker,\n        port=mqtt_port,\n        auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n        retain=True,\n    )\n\n    # Uptime Discovery Message\n    uptime_discovery_message = {\n        &quot;name&quot;: f&quot;Uptime&quot;,\n        &quot;state_topic&quot;: f&quot;apc_pdu_{device_id}\/status\/uptime&quot;,\n        &quot;unique_id&quot;: f&quot;apc_pdu_uptime_{global_serial}_{device_id}&quot;,\n        &quot;icon&quot;: &quot;mdi:timer-outline&quot;,\n        &quot;device&quot;: {\n            &quot;identifiers&quot;: [f&quot;apc_pdu_{snmp_ip_address}_{device_id}&quot;],\n            &quot;name&quot;: f&quot;APC PDU {global_model}&quot;,\n            &quot;model&quot;: global_model,\n            &quot;manufacturer&quot;: &quot;APC&quot;,\n        },\n    }\n\n    # Publishing the Uptime Discovery Message\n    publish.single(\n        f&quot;homeassistant\/sensor\/{device_id}\/uptime\/config&quot;,\n        payload=json.dumps(uptime_discovery_message),\n        hostname=mqtt_broker,\n        port=mqtt_port,\n        auth={&quot;username&quot;: mqtt_user, &quot;password&quot;: mqtt_password},\n        retain=True,\n    )\n\ndef safe_publish(client, topic, payload):\n    try:\n        client.publish(topic, payload)\n    except Exception as e:\n        debug_print(f&quot;Failed to publish MQTT message: {e}&quot;)\n\n\ndef connect_with_retry(client, broker, port, max_retries=5, delay=5):\n    for attempt in range(max_retries):\n        try:\n            client.connect(broker, port, 60)\n            debug_print(&quot;Successfully connected to MQTT broker.&quot;)\n            return True\n        except Exception as e:\n            debug_print(f&quot;Failed to connect to MQTT broker: {e}. Retrying in {delay} seconds...&quot;)\n            time.sleep(delay)\n    debug_print(&quot;Failed to connect after maximum retries.&quot;)\n    return False\n\nif __name__ == &quot;__main__&quot;:\n    client = mqtt.Client()\n    client.username_pw_set(mqtt_user, mqtt_password)\n    client.on_connect = on_connect\n    client.on_message = on_message\n    \n    if connect_with_retry(client, mqtt_broker, mqtt_port):\n        client.loop_start()\n\n        try:\n            while True:\n                publish_status(client)\n                time.sleep(sleep_duration)\n        except KeyboardInterrupt:\n            debug_print(&quot;Script stopped by user.&quot;)\n        finally:\n            client.disconnect()\n    else:\n        debug_print(&quot;Exiting due to connection issues.&quot;)\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">from<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">pysnmp<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">hlapi<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">getCmd<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">setCmd<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">SnmpEngine<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CommunityData<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">UdpTransportTarget<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ContextData<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ObjectType<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ObjectIdentity<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Integer32<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">paho<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">paho<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">publish<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">json<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">time<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Configuration<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;192.168.1.1&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">community_string<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;public&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;192.168.1.2&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\"> = 1883<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;user&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;password&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;it_equitment&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">debug_mode<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">False<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">global_port_names<\/span><span style=\"color: #D4D4D4\"> = {}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">sleep_duration<\/span><span style=\"color: #D4D4D4\"> = 25<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug_mode<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">oid<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">errorIndication<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">errorStatus<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">errorIndex<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">varBinds<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">next<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">getCmd<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">SnmpEngine<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">               <\/span><span style=\"color: #9CDCFE\">CommunityData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">community_string<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mpModel<\/span><span style=\"color: #D4D4D4\">=0),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">               <\/span><span style=\"color: #9CDCFE\">UdpTransportTarget<\/span><span style=\"color: #D4D4D4\">((<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">, 161)),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">               <\/span><span style=\"color: #9CDCFE\">ContextData<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">               <\/span><span style=\"color: #9CDCFE\">ObjectType<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ObjectIdentity<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">oid<\/span><span style=\"color: #D4D4D4\">)))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">errorIndication<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;SNMP Fetch Error: {errorIndication}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">elif<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">errorStatus<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;SNMP Fetch Error Status: {errorStatus.prettyPrint()}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">varBind<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">varBinds<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">varBind<\/span><span style=\"color: #D4D4D4\">[1].<\/span><span style=\"color: #9CDCFE\">prettyPrint<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">control_port<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">oid_base<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">full_oid<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;{oid_base}.{port_num}&quot;<\/span><span style=\"color: #D4D4D4\">  <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">state_value<\/span><span style=\"color: #D4D4D4\"> = 1 <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\"> == 1 <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> 2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Log<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">action<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">being<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">attempted<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">debug_message<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Preparing to send SNMP set command for port {port_num} to {&#39;on&#39; if state == 1 else &#39;off&#39;} (value: {state_value}). OID: {full_oid}&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">debug_message<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">errorIndication<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">errorStatus<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">errorIndex<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">varBinds<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">next<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">setCmd<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">SnmpEngine<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                   <\/span><span style=\"color: #9CDCFE\">CommunityData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;private&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mpModel<\/span><span style=\"color: #D4D4D4\">=0),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                   <\/span><span style=\"color: #9CDCFE\">UdpTransportTarget<\/span><span style=\"color: #D4D4D4\">((<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">, 161)),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                   <\/span><span style=\"color: #9CDCFE\">ContextData<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                   <\/span><span style=\"color: #9CDCFE\">ObjectType<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ObjectIdentity<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">full_oid<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">Integer32<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">state_value<\/span><span style=\"color: #D4D4D4\">)))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">errorIndication<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;SNMP Error: {errorIndication} for port {port_num}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">elif<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">errorStatus<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;SNMP Error: {errorStatus.prettyPrint()} for port {port_num} when attempting to set to {&#39;on&#39; if state == 1 else &#39;off&#39;}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">state_str<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;on&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\"> == 1 <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;off&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/state&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">state_str<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;SNMP set command sent successfully for port {port_num}, updated MQTT with state &#39;{state_str}&#39;.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Exception sending SNMP set command for port {port_num}: {e}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">format_mac_address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">lower<\/span><span style=\"color: #D4D4D4\">().<\/span><span style=\"color: #9CDCFE\">startswith<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;0x&quot;<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">[2:]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">upper<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">formatted_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;:&quot;<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">join<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">i<\/span><span style=\"color: #D4D4D4\">:<\/span><span style=\"color: #9CDCFE\">i<\/span><span style=\"color: #D4D4D4\">+2] <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">i<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">range<\/span><span style=\"color: #D4D4D4\">(0, <\/span><span style=\"color: #9CDCFE\">len<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">), 2))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">formatted_mac<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">publish_status<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">global_serial<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_mac<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_port_names<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global_serial<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;Unknown or Unable to Connect&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;Unknown or Unable to Connect&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;Unknown or Unable to Connect&#39;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">serial_temp<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;.1.3.6.1.4.1.318.1.1.4.1.5.0&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">model_temp<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;.1.3.6.1.4.1.318.1.1.4.1.4.0&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;.1.3.6.1.2.1.2.2.1.6.2&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">serial_temp<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">not<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">global_serial<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">serial_temp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">model_temp<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">not<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">model_temp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">not<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">global_mac<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">format_mac_address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">raw_mac<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">system_uptime_oid<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;.1.3.6.1.2.1.1.3.0&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">system_uptime_ticks<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">system_uptime_oid<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">system_uptime_ticks<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">not<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">system_uptime_readable<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">convert_time_ticks_to_readable_format<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">system_uptime_ticks<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/uptime&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">system_uptime_readable<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/uptime&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Uptime fetch failed&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">port_range<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">range<\/span><span style=\"color: #D4D4D4\">(1, 9) <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> [<\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port_range<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">name_oid<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.{port_num}&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">state_oid<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.{port_num}&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">port_name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">name_oid<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #9CDCFE\">or<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Unknown Port Name&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">port_state<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;on&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">fetch_snmp_data<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">state_oid<\/span><span style=\"color: #D4D4D4\">) == <\/span><span style=\"color: #CE9178\">&#39;1&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;off&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">global_port_names<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">] = <\/span><span style=\"color: #9CDCFE\">port_name<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/name&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port_name<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/ports\/{port_num}\/state&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port_state<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Error updating port {port_num}: {e}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Publish<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">global<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">information<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/serial&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_serial<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/model&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/mac&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_mac<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/status\/identifier&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Ensure<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">messages<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">are<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">published<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">even<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">there<\/span><span style=\"color: #CE9178\">&#39;s an issu<\/span><span style=\"color: #F44747\">e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish_discovery_messages<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Error publishing discovery messages: {e}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">convert_time_ticks_to_readable_format<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">time_ticks<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">int<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">time_ticks<\/span><span style=\"color: #D4D4D4\">) \/ 100  # <\/span><span style=\"color: #9CDCFE\">Convert<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">TimeTicks<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">seconds<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">days<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">\/\/ (24 * 3600)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> % (24 <\/span><span style=\"color: #569CD6\">*<\/span><span style=\"color: #D4D4D4\"> 3600)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">hours<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">\/\/ 3600<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> %= 3600<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">minutes<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">total_seconds<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #6A9955\">\/\/ 60<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;{int(days)} days, {int(hours)} hours, {int(minutes)} minutes&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug_mode<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_topic<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/debug\/logs&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">debug_topic<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">userdata<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">flags<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Connected with result code {rc}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">range<\/span><span style=\"color: #D4D4D4\">(1, 9):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/control\/ports\/{port_num}&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">subscribe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Subscribing to topic: {topic}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_message<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">userdata<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">decode<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;utf-8&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">split<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;\/&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">len<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\">) != 4:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Received message on unexpected topic: {msg.topic}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">return<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">expected_prefix<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;apc_pdu_{device_id}&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">received_prefix<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\">[0]<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Debug<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">output<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">diagnostic<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">purposes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Diagnostic: Expecting prefix &#39;{expected_prefix}&#39;, received &#39;{received_prefix}&#39;&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">received_prefix<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #9CDCFE\">expected_prefix<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\">[1] == <\/span><span style=\"color: #CE9178\">&#39;control&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\">[2] == <\/span><span style=\"color: #CE9178\">&#39;ports&#39;<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">int<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic_parts<\/span><span style=\"color: #D4D4D4\">[3])<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\"> = 1 <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">lower<\/span><span style=\"color: #D4D4D4\">() == <\/span><span style=\"color: #CE9178\">&#39;on&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> 0  # <\/span><span style=\"color: #9CDCFE\">Assuming<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;0&#39;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">correct<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;off&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">control_port<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ValueError<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Error processing command for topic {msg.topic}: {e}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish_debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Received message does not match expected structure: {msg.topic}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">publish_discovery_messages<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">global_serial<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_mac<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">global_port_names<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Publishing<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">each<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">range<\/span><span style=\"color: #D4D4D4\">(1, 9):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port_name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">global_port_names<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">get<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Port {port_num}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">device_name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Port {port_num} - {port_name}&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">device_name<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">ports<\/span><span style=\"color: #D4D4D4\">\/{<\/span><span style=\"color: #9CDCFE\">port_num<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">state<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;command_topic&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_{device_id}\/control\/ports\/{port_num}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_port_{port_num}_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:power-plug&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;payload_on&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;on&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;payload_off&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;off&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;value_template&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;{{ value if value == &#39;on&#39; else &#39;off&#39; }}&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/switch\/apc_pdu_{device_id}\/port_{port_num}\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">port_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Serial<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Number<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">serial_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: &quot;<\/span><span style=\"color: #9CDCFE\">Serial<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Number<\/span><span style=\"color: #D4D4D4\">&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">serial<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_serial_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:alphabetical&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/serial\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">serial_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Model<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">model_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: &quot;<\/span><span style=\"color: #9CDCFE\">Model<\/span><span style=\"color: #D4D4D4\">&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">model<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_model_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:information-outline&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,  <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/model\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">model_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">MAC<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">mac_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: &quot;<\/span><span style=\"color: #9CDCFE\">MAC<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Address<\/span><span style=\"color: #D4D4D4\">&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">mac<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_mac_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:ethernet&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;value_template&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;{{ value }}&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/sensor\/apc_pdu_{device_id}\/mac\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mac_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Identifier<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">identifier_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: &quot;<\/span><span style=\"color: #9CDCFE\">Identifier<\/span><span style=\"color: #D4D4D4\">&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">identifier<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_identifier_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:identifier&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Publishing<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Identifier<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/sensor\/{device_id}\/identifier\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">identifier_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Uptime<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uptime_discovery_message<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">Uptime<\/span><span style=\"color: #D4D4D4\">&quot;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &quot;<\/span><span style=\"color: #9CDCFE\">state_topic<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}\/<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">uptime<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;unique_id&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;apc_pdu_uptime_{global_serial}_{device_id}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;icon&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;mdi:timer-outline&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #CE9178\">&quot;device&quot;<\/span><span style=\"color: #D4D4D4\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            &quot;<\/span><span style=\"color: #9CDCFE\">identifiers<\/span><span style=\"color: #D4D4D4\">&quot;: [<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><span style=\"color: #9CDCFE\">apc_pdu_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">snmp_ip_address<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #9CDCFE\">_<\/span><span style=\"color: #D4D4D4\">{<\/span><span style=\"color: #9CDCFE\">device_id<\/span><span style=\"color: #D4D4D4\">}<\/span><span style=\"color: #CE9178\">&quot;]<\/span><span style=\"color: #F44747\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;name&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;APC PDU {global_model}&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;model&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">global_model<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #CE9178\">&quot;manufacturer&quot;<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #CE9178\">&quot;APC&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    # <\/span><span style=\"color: #9CDCFE\">Publishing<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Uptime<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Discovery<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">single<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;homeassistant\/sensor\/{device_id}\/uptime\/config&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">json<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">dumps<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uptime_discovery_message<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">hostname<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">={&quot;<\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, &quot;<\/span><span style=\"color: #9CDCFE\">password<\/span><span style=\"color: #D4D4D4\">&quot;: <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">retain<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    )<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">safe_publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">payload<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to publish MQTT message: {e}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">connect_with_retry<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">broker<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">max_retries<\/span><span style=\"color: #D4D4D4\">=5, <\/span><span style=\"color: #9CDCFE\">delay<\/span><span style=\"color: #D4D4D4\">=5):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">attempt<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">range<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">max_retries<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">broker<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">port<\/span><span style=\"color: #D4D4D4\">, 60)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Successfully connected to MQTT broker.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">True<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to connect to MQTT broker: {e}. Retrying in {delay} seconds...&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sleep<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">delay<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Failed to connect after maximum retries.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">False<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">__name__<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #CE9178\">&quot;__main__&quot;<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Client<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">username_pw_set<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mqtt_user<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">on_connect<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">on_connect<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">on_message<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">on_message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">connect_with_retry<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">loop_start<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">while<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">publish_status<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sleep<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">sleep_duration<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">KeyboardInterrupt<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Script stopped by user.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">finally<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">disconnect<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">debug_print<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Exiting due to connection issues.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Guide for SNMP and MQTT Integration Script This is a script I developed to retrieve status information from my APC PDU. While there may be other solutions available, I chose &#8230;<\/p>\n","protected":false},"author":1,"featured_media":7167,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"footnotes":""},"categories":[352,355,354,353],"tags":[],"class_list":["post-7166","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-coding","category-home-assistant","category-linux","category-python"],"_links":{"self":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7166","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7166"}],"version-history":[{"count":22,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7166\/revisions"}],"predecessor-version":[{"id":7661,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7166\/revisions\/7661"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/media\/7167"}],"wp:attachment":[{"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}