"use strict";(globalThis.webpackChunkdocs_split_developer=globalThis.webpackChunkdocs_split_developer||[]).push([[5154],{4421:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>d,default:()=>g,frontMatter:()=>o,metadata:()=>r,toc:()=>c});const r=JSON.parse('{"id":"debugging","title":"Debugging Guide","description":"Tips and techniques for debugging the Tibber Prices integration during development.","source":"@site/docs/debugging.md","sourceDirName":".","slug":"/debugging","permalink":"/hass.tibber_prices/developer/debugging","draft":false,"unlisted":false,"editUrl":"https://github.com/jpawlowski/hass.tibber_prices/tree/main/docs/developer/docs/debugging.md","tags":[],"version":"current","lastUpdatedAt":1764985026000,"frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Critical Behavior Patterns - Testing Guide","permalink":"/hass.tibber_prices/developer/critical-patterns"},"next":{"title":"Period Calculation Theory","permalink":"/hass.tibber_prices/developer/period-calculation-theory"}}');var s=i(4848),t=i(8453);const o={},d="Debugging Guide",l={},c=[{value:"Logging",id:"logging",level:2},{value:"Enable Debug Logging",id:"enable-debug-logging",level:3},{value:"Key Log Messages",id:"key-log-messages",level:3},{value:"VS Code Debugging",id:"vs-code-debugging",level:2},{value:"Launch Configuration",id:"launch-configuration",level:3},{value:"Set Breakpoints",id:"set-breakpoints",level:3},{value:"pytest Debugging",id:"pytest-debugging",level:2},{value:"Run Single Test with Output",id:"run-single-test-with-output",level:3},{value:"Debug Test in VS Code",id:"debug-test-in-vs-code",level:3},{value:"Useful Test Patterns",id:"useful-test-patterns",level:3},{value:"Common Issues",id:"common-issues",level:2},{value:"Integration Not Loading",id:"integration-not-loading",level:3},{value:"Sensors Not Updating",id:"sensors-not-updating",level:3},{value:"Period Calculation Wrong",id:"period-calculation-wrong",level:3},{value:"Performance Profiling",id:"performance-profiling",level:2},{value:"Time Execution",id:"time-execution",level:3},{value:"Memory Usage",id:"memory-usage",level:3},{value:"Profile with cProfile",id:"profile-with-cprofile",level:3},{value:"Live Debugging in Running HA",id:"live-debugging-in-running-ha",level:2},{value:"Remote Debugging with debugpy",id:"remote-debugging-with-debugpy",level:3},{value:"IPython REPL",id:"ipython-repl",level:3}];function a(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"debugging-guide",children:"Debugging Guide"})}),"\n",(0,s.jsx)(n.p,{children:"Tips and techniques for debugging the Tibber Prices integration during development."}),"\n",(0,s.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,s.jsx)(n.h3,{id:"enable-debug-logging",children:"Enable Debug Logging"}),"\n",(0,s.jsxs)(n.p,{children:["Add to ",(0,s.jsx)(n.code,{children:"configuration.yaml"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"logger:\n default: info\n logs:\n custom_components.tibber_prices: debug\n"})}),"\n",(0,s.jsx)(n.p,{children:"Restart Home Assistant to apply."}),"\n",(0,s.jsx)(n.h3,{id:"key-log-messages",children:"Key Log Messages"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Coordinator Updates:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[custom_components.tibber_prices.coordinator] Successfully fetched price data\n[custom_components.tibber_prices.coordinator] Cache valid, using cached data\n[custom_components.tibber_prices.coordinator] Midnight turnover detected, clearing cache\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Period Calculation:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[custom_components.tibber_prices.coordinator.periods] Calculating BEST PRICE periods: flex=15.0%\n[custom_components.tibber_prices.coordinator.periods] Day 2024-12-06: Found 2 periods\n[custom_components.tibber_prices.coordinator.periods] Period 1: 02:00-05:00 (12 intervals)\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"API Errors:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[custom_components.tibber_prices.api] API request failed: Unauthorized\n[custom_components.tibber_prices.api] Retrying (attempt 2/3) after 2.0s\n"})}),"\n",(0,s.jsx)(n.h2,{id:"vs-code-debugging",children:"VS Code Debugging"}),"\n",(0,s.jsx)(n.h3,{id:"launch-configuration",children:"Launch Configuration"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:".vscode/launch.json"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "version": "0.2.0",\n "configurations": [\n {\n "name": "Home Assistant",\n "type": "debugpy",\n "request": "launch",\n "module": "homeassistant",\n "args": ["-c", "config", "--debug"],\n "justMyCode": false,\n "env": {\n "PYTHONPATH": "${workspaceFolder}/.venv/lib/python3.13/site-packages"\n }\n }\n ]\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"set-breakpoints",children:"Set Breakpoints"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Coordinator update:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'# coordinator/core.py\nasync def _async_update_data(self) -> dict:\n """Fetch data from API."""\n breakpoint() # Or set VS Code breakpoint\n'})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Period calculation:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'# coordinator/period_handlers/core.py\ndef calculate_periods(...) -> list[dict]:\n """Calculate best/peak price periods."""\n breakpoint()\n'})}),"\n",(0,s.jsx)(n.h2,{id:"pytest-debugging",children:"pytest Debugging"}),"\n",(0,s.jsx)(n.h3,{id:"run-single-test-with-output",children:"Run Single Test with Output"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:".venv/bin/python -m pytest tests/test_period_calculation.py::test_midnight_crossing -v -s\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Flags:"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"-v"})," - Verbose output"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"-s"})," - Show print statements"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"-k pattern"})," - Run tests matching pattern"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"debug-test-in-vs-code",children:"Debug Test in VS Code"}),"\n",(0,s.jsx)(n.p,{children:'Set breakpoint in test file, use "Debug Test" CodeLens.'}),"\n",(0,s.jsx)(n.h3,{id:"useful-test-patterns",children:"Useful Test Patterns"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Print coordinator data:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'def test_something(coordinator):\n print(f"Coordinator data: {coordinator.data}")\n print(f"Price info count: {len(coordinator.data[\'priceInfo\'])}")\n'})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Inspect period attributes:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"def test_periods(hass, coordinator):\n periods = coordinator.data.get('best_price_periods', [])\n for period in periods:\n print(f\"Period: {period['start']} to {period['end']}\")\n print(f\" Intervals: {len(period['intervals'])}\")\n"})}),"\n",(0,s.jsx)(n.h2,{id:"common-issues",children:"Common Issues"}),"\n",(0,s.jsx)(n.h3,{id:"integration-not-loading",children:"Integration Not Loading"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Check:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'grep "tibber_prices" config/home-assistant.log\n'})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Common causes:"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Syntax error in Python code \u2192 Check logs for traceback"}),"\n",(0,s.jsxs)(n.li,{children:["Missing dependency \u2192 Run ",(0,s.jsx)(n.code,{children:"uv sync"})]}),"\n",(0,s.jsxs)(n.li,{children:["Wrong file permissions \u2192 ",(0,s.jsx)(n.code,{children:"chmod +x scripts/*"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"sensors-not-updating",children:"Sensors Not Updating"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Check coordinator state:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"# In Developer Tools > Template\n{{ states.sensor.tibber_home_current_interval_price.last_updated }}\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Debug in code:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'# Add logging in sensor/core.py\n_LOGGER.debug("Updating sensor %s: old=%s new=%s",\n self.entity_id, self._attr_native_value, new_value)\n'})}),"\n",(0,s.jsx)(n.h3,{id:"period-calculation-wrong",children:"Period Calculation Wrong"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Enable detailed period logs:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"# coordinator/period_handlers/period_building.py\n_LOGGER.debug(\"Candidate intervals: %s\",\n [(i['startsAt'], i['total']) for i in candidates])\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Check filter statistics:"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[period_building] Flex filter blocked: 45 intervals\n[period_building] Min distance blocked: 12 intervals\n[period_building] Level filter blocked: 8 intervals\n"})}),"\n",(0,s.jsx)(n.h2,{id:"performance-profiling",children:"Performance Profiling"}),"\n",(0,s.jsx)(n.h3,{id:"time-execution",children:"Time Execution"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'import time\n\nstart = time.perf_counter()\nresult = expensive_function()\nduration = time.perf_counter() - start\n_LOGGER.debug("Function took %.3fs", duration)\n'})}),"\n",(0,s.jsx)(n.h3,{id:"memory-usage",children:"Memory Usage"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'import tracemalloc\n\ntracemalloc.start()\n# ... your code ...\ncurrent, peak = tracemalloc.get_traced_memory()\n_LOGGER.debug("Memory: current=%d peak=%d", current, peak)\ntracemalloc.stop()\n'})}),"\n",(0,s.jsx)(n.h3,{id:"profile-with-cprofile",children:"Profile with cProfile"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"python -m cProfile -o profile.stats -m homeassistant -c config\npython -m pstats profile.stats\n# Then: sort cumtime, stats 20\n"})}),"\n",(0,s.jsx)(n.h2,{id:"live-debugging-in-running-ha",children:"Live Debugging in Running HA"}),"\n",(0,s.jsx)(n.h3,{id:"remote-debugging-with-debugpy",children:"Remote Debugging with debugpy"}),"\n",(0,s.jsx)(n.p,{children:"Add to coordinator code:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'import debugpy\ndebugpy.listen(5678)\n_LOGGER.info("Waiting for debugger attach on port 5678")\ndebugpy.wait_for_client()\n'})}),"\n",(0,s.jsx)(n.p,{children:"Connect from VS Code with remote attach configuration."}),"\n",(0,s.jsx)(n.h3,{id:"ipython-repl",children:"IPython REPL"}),"\n",(0,s.jsx)(n.p,{children:"Install in container:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"uv pip install ipython\n"})}),"\n",(0,s.jsx)(n.p,{children:"Add breakpoint:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"from IPython import embed\nembed() # Drops into interactive shell\n"})}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsxs)(n.p,{children:["\ud83d\udca1 ",(0,s.jsx)(n.strong,{children:"Related:"})]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/hass.tibber_prices/developer/testing",children:"Testing Guide"})," - Writing and running tests"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/hass.tibber_prices/developer/setup",children:"Setup Guide"})," - Development environment"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/hass.tibber_prices/developer/architecture",children:"Architecture"})," - Code structure"]}),"\n"]})]})}function g(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}}}]);