Monitoring with a Xiaomi Dafang

logo
xiaomi dafang camera

The Xiaomi Dafang is a relatively cheap wifi accessible camera. When I chose to buy this camera I was sure that I was not going to use the official Xiaomi software that came with it. I was aware of custom firmware that I could install that probably would give me more control of the device than the original software would allow. With the custom firmware, for one, I could restrict the network access of the camera to my local area network. You cannot use the official software without the camera accessing the internet. The official software most probably has more features than the EliasKotlyar firmware and most people will have no issues with their camera accessing the internet. In the rare occasions that the internet is down, however, they will not be able to use the camera.

Details of the custom firmware and its installation are at its site. Perhaps the only difficulty I had in installing the custom firmware was in accessing the microsd card slot at the base of the device.

With the custom firmware Dafang becomes a linux box with a camera that you can ssh into. Most routers these days allow you to associate a MAC address with a fixed local ip address that their DHCP servers will allot when the device with that MAC address comes on. This ensures that you don't have to find out the ip address to ssh into every time.

When you copy the firmware files onto the microsd card using your laptop one file you will have to create and edit is wpa_supplicant.conf in the config folder. Create the file as a copy of wpa_supplicant.conf.dist which already exists. Then edit the file to include the ssid and password of the router that is your wifi access point. Now Dafang will have wifi access when it is switched on with the card plugged into the microsd slot. You can access it from your laptop using your browser at https://dafang's_local_ip-address. The default user name and password are root and ismart12. There are other files that you may want to edit to make Dafang run the way you want. But that can wait until you ssh into the device after it is switched on.

The ready-to-run executables made available for you are found in the /system/sdcard/bin/ folder. There is an http server(lighttpd), an ssh server(dropbearmulti), curl, an executable to capture an image from the camera, getimage, and many more. Some of these executables such as lighttpd, rtsp etc are run through scripts in /system/sdcard/controlscripts/. These scripts use custom configuration data stored in appropriately named files in /system/sdcard/config. We have already created one custom configuration file in wpa_supplicant.conf that started out as a copy of wpa-supplicant.conf.dist. Similarly, to customize, say ssh settings, you copy ssh.conf.dist to ssh.conf and edit it to your needs. To make changes in the programs that are started when the device boots up, add or remove entries from the folder /system/sdcard/config/autostart/ which are single-line scripts that call the corresponding controlscripts entry. The autostart entries are run from the script /system/sdcard/run.sh which, if you want, you can manually edit yourself. I have edited it to turn on the infrared leds when the system comes up since I use the device usually at night for monitoring.

Most of the time you don't have to edit the configuration files yourself. That's what the web ui is for.

For monitoring, motion detection is almost an absolute requirement and the EliasKotlyar firmware gives you configurable motion detection. Scripts placed in /system/sdcard/config/userscripts/motiondetection/ will be run when motion is detected. These scripts are run from /system/sdcard/scripts/detectionOn.sh. The first argument to each such script is the string "on" and the second argument is the image snapshot file recorded by the camera at that time.

I have the following script, upload_image_to_desktop.sh, in the motiondetection folder.

/system/sdcard/bin/curl -F "dafang_img=@$2" http://192.168.0.12:3456/upload 2>/dev/null

The -F option makes curl simulate the submission of a form. Here, I am sending the image snapshot recorded by the camera as a file named dafang_img to the url http://192.168.0.12:3456/upload which is served by a program running on my desktop at that address. The server program then uses the image viewer program, feh, to display the received image as a pop-up. It also plays a sound that helps notify me if I have dozed off sitting in front of the desktop. Here is the simple server program that I run on my desktop while monitoring with the Dafang.

package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
)

var errLog, infoLog *log.Logger

func playSound() {
cmd := exec.Command("/usr/bin/aplay", "/home/my_user_name/Audio/beep.wav")
err := cmd.Run()
if err != nil {
errLog.Println(err)
} else {
infoLog.Printf("Playing sound")
}
}

func showImg(imgName string) {
cmd := exec.Command("feh", "-g640x360+5+30", "--scale-down", imgName)
err := cmd.Run()
if err != nil {
errLog.Println(err)
} else {
infoLog.Printf("Showing image %s\n", imgName)
}
}

func uploadFile(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(10 << 20)
file, _, err := r.FormFile("dafang_img")
if err != nil {
errLog.Println("Error getting uploaded file ", err)
return
}
defer file.Close()
tmpFile, err := ioutil.TempFile("dafang_images", "dafang_*.jpg")
if err != nil {
errLog.Println(err)
}
defer tmpFile.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
errLog.Println(err)
}
tmpFile.Write(fileBytes)
if absPath, err := filepath.Abs(tmpFile.Name()); err == nil {
go showImg(absPath)
go playSound()
}
fmt.Fprintf(w, "Successfully received file\n")
}

func main() {
infoFile, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
log.Fatal(err)
}
defer infoFile.Close()
infoLog = log.New(infoFile, "INFO\t", log.Ldate|log.Ltime)

errFile, err := os.OpenFile("err.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
log.Fatal(err)
}
defer errFile.Close()
errLog = log.New(errFile, "ERROR\t", log.Ldate|log.Ltime)

http.HandleFunc("/upload", uploadFile)
http.ListenAndServe(":3456", nil)
}

Outside of motion detection, you can retrieve an image from the camera using the url, https://dafang's_local-ip-address/cgi-bin/currentpicoptim.cgi. This runs the getimage executable.

There is also the executable motor that can be used to rotate the camera about the vertical or horizontal axis.

The EliasKotlyar software also has utilities for alerting you through email or telegram or matrix messaging but I have not used them yet.