Running Jan on your homelab means you have a local LLM with an API. Home Assistant has automation rules. The obvious next move is to connect Jan to Home Assistant so your smart home can actually understand natural language. It sounds cleaner in theory than it works in practice, but if you know the gaps, it’s genuinely useful.

Why Connect Jan to Home Assistant at All
Home Assistant’s built-in AI stuff either routes through the cloud or relies on older, smaller models. Jan runs whatever you want locally, and it exposes an OpenAI-compatible API on port 1337 by default. That’s the lever you need.
The real upside: voice intents that understand context. Instead of “turn on the lights in the bedroom,” you can feed natural language directly to Jan, parse the response, and trigger actual automations. Or use it to generate summaries of your home’s activity. Or just have a chatbot that knows your device names without cloud calls.
The caveat: Home Assistant doesn’t have native Jan support. You’re gluing it together with REST calls and templates. That’s not a dealbreaker, but it means more configuration and more things that can silently fail.
Prerequisites and Hardware
You need Jan and Home Assistant running on the same network. Jan should be on a stable machine with at least 8GB of RAM; 16GB is safer if you’re also running Home Assistant on the same box. Both can coexist fine on a single moderate-spec Intel NUC or comparable.
Jan must be exposed on your local network. If you’re only running it on localhost, Home Assistant can’t reach it. For this setup, I’m assuming both are on the same LAN with fixed IPs or hostnames.
You’ll need a model loaded in Jan. I’ve tested this with Mistral 7B and Llama 2 13B. Smaller models are faster but less accurate at understanding intent. Start with a 7B model if you’re unsure what to use.
Step 1: Expose Jan’s API Properly
Out of the box, Jan’s API server listens on 127.0.0.1:1337. Home Assistant can’t reach it from another machine. You need to change the bind address.
Jan’s config lives in different places depending on your OS. On Linux, it’s typically ~/.jan/settings.json. On Mac, it’s in ~/Library/Application Support/Jan. Open the settings file and look for the API section.
You should see something like this (the file structure varies slightly by version, but the pattern is consistent):
{
"api": {
"host": "127.0.0.1",
"port": 1337,
"corsEnabled": false
},
"models": [
// model list here
]
}
Change "host": "127.0.0.1" to "host": "0.0.0.0". This makes Jan listen on all network interfaces. Also set "corsEnabled": true because Home Assistant will be making cross-origin requests.
Save and restart Jan. Verify the API is accessible from another machine on your network by testing a simple curl:
curl http://[jan-machine-ip]:1337/v1/models
You should get back a JSON list of loaded models. If you get a connection refused or timeout, Jan’s API isn’t exposed yet. Check that Jan is actually running and the settings changes took effect.
Step 2: Configure Home Assistant to Call Jan
Home Assistant needs a way to send requests to Jan and parse responses. The cleanest approach is using the rest integration combined with a template sensor and an automation.
In your Home Assistant configuration.yaml, add a REST sensor that calls Jan’s chat completion endpoint:
The gear I run for this
Hardware from my own homelab, relevant to this guide โ direct Amazon links.
Affiliate links โ I earn a small commission at no extra cost to you. Browse my full homelab store →
rest:
- scan_interval: 3600
resource: http://[jan-machine-ip]:1337/v1/chat/completions
method: POST
name: Jan LLM
headers:
Content-Type: application/json
payload: |
{
"model": "mistral",
"messages": [{
"role": "user",
"content": "{{ state_attr('input_text.llm_prompt', 'value') }}"
}],
"temperature": 0.7,
"max_tokens": 500
}
value_template: "{{ value_json.choices[0].message.content }}"
json_attributes:
- usage
This assumes you create an input_text helper called llm_prompt where you feed the prompt. The response gets stored in the sensor state.
Restart Home Assistant after adding this. Check the developer tools under States to confirm the sensor appears.
Step 3: Wire It Into an Automation
Raw REST sensors are passive. You need an automation to trigger them and act on the response.
Here’s an example that listens for voice input via Home Assistant’s conversation integration, sends it to Jan, and logs the response:
automation:
- alias: Query Jan LLM
trigger:
platform: state
entity_id: input_text.llm_prompt
action:
- service: rest.get_template_sensor
target:
entity_id: sensor.jan_llm
- service: logger.write
data:
message: "Jan response: {{ state_attr('sensor.jan_llm', 'response') }}"
- service: tts.google_translate_say
data:
entity_id: media_player.living_room
message: "{{ states('sensor.jan_llm') }}"
This is a basic flow. Real usage gets more complex because you’ll want to parse intent from Jan’s response and trigger specific automations. You might add a template to extract device names or actions from the LLM output, then use that to call the right light.turn_on or climate.set_temperature service.
Where This Gets Messy
The honest part: Jan’s responses aren’t always structured. If you ask it to turn on the lights, it might respond with “I’ll turn on the lights” or “Turning on the lights now” or “Lights are on” depending on the model and temperature setting. Parsing intent from free-form text is doable but adds another layer of complexity.
One workaround is to prompt Jan with a specific format. Ask it to respond with JSON:
"content": "The user said: {{ prompt }}. Respond ONLY with valid JSON in this format: {"action": "turn_on", "device": "bedroom_lights", "confidence": 0.95}"
Models are reasonably good at this, but not perfect. Mistral 7B follows this instruction about 90% of the time in my testing. Llama 2 was closer to 75%. The remaining failures require error handling.
Also, Jan’s API can be slow. A Mistral 7B inference takes 3-5 seconds on a modest GPU, longer on CPU. If you’re using this for real-time voice control, expect noticeable latency. It’s fine for batch summaries or offline analysis. It’s frustrating for voice intents.
Testing the Integration
Start with a simple prompt. Open Developer Tools in Home Assistant, go to the States tab, and manually set the input_text.llm_prompt to something like “What is the current time?”
Wait 5-10 seconds for Jan to respond. Check the sensor.jan_llm state. If it populated with an answer, the connection works.
Then test something that requires intent parsing: “Turn on the bedroom lights.” Store Jan’s response. If it says “I’ll turn on the bedroom lights” or something similar, your automation can extract the intent. If it says “I don’t know what bedroom lights are,” your model might be too small or poorly prompted.
This is where you discover whether your setup is actually useful or just technically working. The testing phase takes longer than the configuration phase, honestly.
Security Note
Exposing Jan’s API on 0.0.0.0 on your LAN is fine. Anyone on your network can query it, which might matter if you share the network or have guests. For a truly locked-down setup, use a firewall rule or keep it on a VLAN.
Also note that Home Assistant’s REST sensor will expose your Jan API URL in its state if you log it. Nothing catastrophic, but worth knowing.
FAQ
Can Jan run on the same machine as Home Assistant?
Yes. If Home Assistant is containerized, expose Jan’s API on the Docker host’s IP. If both run natively, Jan can bind to 0.0.0.0:1337 and Home Assistant calls it directly. RAM usage is the constraint, not architecture.
What if Jan crashes or becomes unresponsive?
The REST sensor call will timeout after 10 seconds by default. Home Assistant logs the error and moves on. Add a timeout check in your automation to avoid getting stuck. You can also use a template condition to verify the sensor state before triggering voice output.
Can I use Jan with Home Assistant’s conversation integration?
Not directly. Home Assistant’s native conversation system expects specific response formats that Jan doesn’t always follow. The REST sensor approach is more reliable because you control the prompt structure.
How much slower is this than cloud-based AI?
Mistral 7B takes 3-5 seconds per request on a 4GB VRAM GPU, longer on CPU. Cloud APIs respond in under a second usually. For voice intents, the difference is noticeable. For batch operations like generating a summary of the day’s activity, it doesn’t matter.
Does Jan need a GPU to work with Home Assistant?
No, but CPU inference is slow. A model that takes 5 seconds on GPU takes 45 seconds on CPU. If you’re testing or don’t care about latency, CPU is fine. For real use, a GPU helps a lot.
Explore Jan in our AI Homelab Toolkit.