Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,45 @@
"format": "prettier --write ."
},
"devDependencies": {
"@content-collections/core": "^0.13.0",
"@content-collections/core": "^0.13.1",
"@content-collections/vite": "^0.2.8",
"@eslint/compat": "^2.0.0",
"@eslint/js": "^9.39.2",
"@fontsource/roboto": "^5.2.9",
"@fontsource/spectral": "^5.2.8",
"@lucide/svelte": "^0.562.0",
"@maiertech/sveltekit-helpers": "^0.43.1",
"@maiertech/sveltekit-helpers": "^0.44.0",
"@playwright/test": "^1.57.0",
"@stackblitz/sdk": "^1.11.0",
"@sveltejs/adapter-node": "^5.4.0",
"@sveltejs/enhanced-img": "^0.9.2",
"@sveltejs/kit": "^2.49.2",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@sveltejs/kit": "^2.49.3",
"@sveltejs/vite-plugin-svelte": "^6.2.3",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^24.10.4",
"d3-array": "^3.2.4",
"dotenv": "^17.2.3",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.13.1",
"eslint-plugin-svelte": "^3.14.0",
"globals": "^16.5.0",
"mdsvex": "^0.12.6",
"mode-watcher": "^1.1.0",
"prettier": "^3.7.4",
"prettier-plugin-svelte": "^3.4.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"shiki": "^3.20.0",
"simple-icons": "^16.2.0",
"svelte": "^5.46.0",
"shiki": "^3.21.0",
"simple-icons": "^16.4.0",
"svelte": "^5.46.1",
"svelte-check": "^4.3.5",
"sveltekit-embed": "^0.0.22",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.0",
"vite": "^7.3.0",
"typescript-eslint": "^8.52.0",
"vite": "^7.3.1",
"vite-plugin-devtools-json": "^1.0.0",
"zod": "^4.2.1"
"zod": "^4.3.5"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
747 changes: 391 additions & 356 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/collections/posts/lastmod.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
"src/routes/posts/(2025)/dropping-requests-in-sveltekit/+page.md": "2025-11-05T14:06:22.000Z",
"src/routes/posts/(2025)/environment-variables-in-sveltekit/+page.md": "2025-11-05T14:06:22.000Z",
"src/routes/posts/(2025)/it-aint-easy-to-move-a-side-project-off-big-tech/+page.md": "2025-11-07T20:24:14.000Z",
"src/routes/posts/(2025)/managing-environment-variables-with-vercel/+page.md": "2025-11-12T20:58:01.000Z"
"src/routes/posts/(2025)/managing-environment-variables-with-vercel/+page.md": "2025-11-12T20:58:01.000Z",
"src/routes/posts/(2026)/the-privacy-friendly-video-doorbell-that-failed-in-cold-weather/+page.md": "2026-01-09T16:49:30.000Z"
}
5 changes: 5 additions & 0 deletions src/collections/tags/iot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "iot",
"label": "IoT",
"path": "/tags/iot"
}
4 changes: 2 additions & 2 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
<div class="isolate flex min-h-screen flex-col gap-8 sm:gap-10 lg:gap-12">
<SiteHeader
links={[
{ text: 'Posts', href: '/posts' },
{ text: 'Notes', href: '/notes' }
{ title: 'Posts', href: '/posts' },
{ title: 'Notes', href: '/notes' }
]}
class="z-10 shrink-0"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: The privacy-friendly video doorbell that failed in cold weather
author: thilo
publishedDate: 2026-01-10
description:
A Reolink video doorbell promised to be privacy-friendly, but failed in cold weather with poor
event detection and severe battery drain.
tags:
- iot
---

<script>
import { Figure } from '@maiertech/sveltekit-helpers';
import DoorbellImage from './DoorbellImage.svelte';
</script>

During the holidays, I installed a
[Reolink Video Doorbell (Battery)](https://reolink.com/nl/product/reolink-doorbell-battery/) on my
front door. After a honeymoon that lasted a few days, winter came to the Netherlands and with
freezing temperatures my excitement for this doorbell quickly reached a freezing point. But more on
that in a minute.

About 2 years ago, I had a
[Google Nest Doorbell (Battery)](https://store.google.com/product/nest_doorbell_battery?hl=nl) for
about 6 months. After the first mild Dutch winter, its image started flickering and when I removed
it for a reset, the mounting mechanism broke. A common problem with this model. To Google's credit,
I received a full refund. But I started to wonder whether it's a good idea to install an IoT device
in a spot where it is exposed to the full range from dry freezing cold to scorching hot humid
weather with direct sun exposure and occasional heavy rain splashes.

Fast forward to late 2025. I wanted to give a video doorbell another try. But this time, I wanted to
bypass Big Tech and go for a model that works locally without subscription and without the cloud.
After digging through endless negative doorbell reviews, I settled on Reolink. Their battery
doorbell ticked all the boxes: local storage, no subscription required, optional wired installation,
works with my mechanical chime, battery-powered (in case of a power outage), and affordable. And a
beautiful piece of hardware, IP65 rated, that works in a temperature range from -10°C to +55°C. At
least that's what the specs say.

<Figure caption="The Reolink Video Doorbell (Battery) looks stunning but fails in cold weather." class="mb-8 max-w-xs">
<DoorbellImage />
</Figure>

The first few days, while the temperature was still close to +10°C, the doorbell worked almost
flawlessly. It kept trickle-charging the battery back to 100%. And triggers worked reasonably well.
But I noticed some firmware quirks.

But let me first explain my constraints. Dutch neighborhoods are dense, and therefore, my doorbell
camera (like many other doorbell cameras in the Netherlands) captures a public sidewalk. I don't
want to capture anything happening in a public area. It's none of my business. I want to capture
only what happens on my property. Google Nest offers intuitive detection zones for this scenario.
Just mark a detection zone located on my property and Google will alert me if someone steps into
that zone. Anything happening outside gets ignored. My neighbor can walk his dog on the sidewalk
without me ever knowing about it.

Reolink reverses this logic. It offers non-detection zones. Reolink does not disclose the logic of
non-detection zones. But from what I can tell, anything touching a non-detection zone gets ignored.
That's a problem when the public sidewalk is in the center of the camera view and it's literally
impossible to walk to my front door without touching the non-detection zone. In my case,
non-detection zones broke meaningful event detection.

As an alternative, you can enable or disable detection based on object size. For instance, someone
walking on the sidewalk across the street will appear small in the camera view and can be ignored.
But the mailman approaching my front door will at one point appear large enough to trigger an alert.
But this approach is very unreliable. My son's playdate was small enough to evade detection until
they rang the doorbell.

Another quirk was that whenever someone left the house, event detection would not trigger. I
literally managed to take the above picture of the doorbell without triggering an alert. This made
me wonder whether person detection is based on an object getting larger. If you leave the house, you
never get larger in the camera view, only smaller. But I'm just guessing here.

Then winter came and with temperatures below +5°C, the doorbell started behaving erratically. The
battery stopped charging and started draining quickly despite being wired up to the doorbell
transformer. I get it that the battery won't charge if temperatures drop below 0°C. But the battery
should not drain when wired. The other issue was that at low temperatures, motion detection kept
failing. I could walk up to the doorbell without triggering an alert. Within a few days, you reach a
point where you have to detach the doorbell, remove the wires and bring it inside for charging.
That's absurd for a wired video doorbell.

The last nail in the doorbell's coffin was customer support. You get the usual remove it, reset it
and re-install it. But the moment I asked to for a return label and a refund, the response speed
slowed down. I felt like I was being put through all kinds of hoops to discourage me from returning
the doorbell.

I wanted to like this doorbell. There are so few options out there for privacy-conscious consumers.
Reolink has a whole range of privacy-friendly cameras, including affordable PoE cameras. Therefore,
when I ended up with a choice between a privacy-friendly video doorbell with flawed event detection
and a Big Tech surveillance device that nickels and dimes me for flawless event detection, I felt
stuck between a rock and a hard place.

For the time being, I reverted back to a dumb doorbell in combination with an old Google Nest
camera. The camera is attached from the inside with a suction cup holder to a window at the
entrance. Event detection works flawlessly, no matter how cold it is outside. But I have to shell
out a subscription fee to Big Tech.

This feels like a defeat. But I hope that it's temporary and that with
[Matter having added support for cameras in v1.5](https://matter-smarthome.de/en/development/matter-1-5-arrives-bringing-long-awaited-cameras/),
there will be more privacy-friendly camera options with flawless event detection in the near future.
And I hope Reolink will iterate on their video doorbell to make it work reliably in cold weather.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import src from './reolink-doorbell.jpeg?enhanced';
</script>

<enhanced:img {src} alt="The Reolink Video Doorbell (Battery) installed at my front door." />
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.