Hikvision Camera Linecrossing detection

All kinds of 'OS' scripts

Moderator: leecollings

Post Reply
Andyyyy
Posts: 29
Joined: Saturday 13 July 2013 23:46
Target OS: -
Domoticz version:
Contact:

Hikvision Camera Linecrossing detection

Post by Andyyyy »

Hi all,
i take the script form ccontavalli (https://github.com/ccontavalli/hicknotify) and change it a little bit to get the linecrossing function from my hikvision to domoticz on my Rpi3.

The script is written in golang.

install golang:

Code: Select all

pi@Domoticz:~ $ sudo apt install golang
copy hiknotify.go and config.json to /domoticz/scripts/ipcamera/

hiknotify.go

Code: Select all

package main

import "fmt"
import "net/http"
import "bufio"
import "sync"
import "bytes"
import "regexp"
import "strconv"
import "time"
import "encoding/json"
import "os"

type Event struct {
  etype string
  estate string
  ecount int
  camera *Camera
}

func (e *Event) Complete() bool {
  if len(e.etype) > 0 && len(e.estate) > 0 && e.ecount > 0 {
    return true
  }
  return false
}
func (e *Event) Reset() {
  *e = Event{}
}

func GenerateTimeout(config Config, camera *Camera, lc chan bool, ec chan Event) {
  count := 1
  for {
    select {
      case <-lc:
        break;

      case <-time.After(time.Second * config.WatchdogTime):
        ec <- Event{"watchdog", "lost-signal", count, camera}
        count += 1
        break

    }
  }
}

func GenerateEvents(wg *sync.WaitGroup, config Config, camera Camera, ec chan Event) {
  var last_attempt time.Time

  lc := make(chan bool)
  event := Event{camera: &camera}
  defer wg.Done()

  go GenerateTimeout(config, &camera, lc, ec)

  for {
    if time.Now().Before(last_attempt.Add(time.Second * config.ErrorRetryTime)) {
      fmt.Println("SLEEPING FOR SECONDS", config.ErrorRetryTime)
      time.Sleep(config.ErrorRetryTime * time.Second)
    }
    last_attempt = time.Now()

    client := &http.Client{}
    // This will break the stream of responses, the response has
    // to complete within 10 seconds.
    // client.Timeout = time.Second * 10

    etyper := regexp.MustCompile("eventType>(.*)</eventType")
    estater := regexp.MustCompile("eventState>(.*)</eventState")
    ecountr := regexp.MustCompile("activePostCount>(.*)</activePostCount")
	
    request, err := http.NewRequest("GET", camera.Url, nil)
    if err != nil {
      fmt.Println("REQUEST ERROR", camera, err)
      continue
    }

    request.SetBasicAuth(camera.Username, camera.Password)

    resp, err := client.Do(request)
    if err != nil {
      fmt.Println("DO ERROR", camera, err)
      continue
    }

    reader := bufio.NewReader(resp.Body)
    for {
      line, err := reader.ReadBytes('\n')
      if err != nil {
        fmt.Println("READER ERROR", camera, err)
        break
      }
      // Send keepalive
      lc <- true
      //Uncomment this line to dump all notifications
      fmt.Println(string(line))

      line = bytes.TrimRight(line, "\n\r")
	  
      etypes := etyper.FindSubmatch(line)
      if len(etypes) > 0 {
        event.etype = string(etypes[1])
      }
      estates := estater.FindSubmatch(line)
      if len(estates) > 0 {
        event.estate = string(estates[1])
      }
      ecounts := ecountr.FindSubmatch(line)
      if len(ecounts) > 0 {
        count, _ := strconv.Atoi(string(ecounts[1]))
        event.ecount = count + 1
      }
      if event.Complete() {
        if event.etype != "videoloss" {
        //if event.etype == "videoloss" {
          ec <- event
		//fmt.Println("SENDING NOTIFICATION FOR", event.etype, event.estate, event.ecount)
        }
	        event.Reset()
        event.camera = &camera
      }
    }
  }
}


type Camera struct {
  Url string
  Name string
  Username string
  Password string

}



type Config struct {
  Cameras []Camera
  DomoticzHost string
  DomoticzPort string
  DomoticzBasicAuth bool
  DomoticzUsername string
  DomoticzPassword string
  LineCrossidx string

  DampeningTime time.Duration
  ErrorRetryTime time.Duration
  WatchdogTime time.Duration
}

func LoadConfig() (Config, error) {
  file, err := os.Open("/home/pi/domoticz/scripts/ipcamera/config.json")
  if err != nil {
    return Config{}, err
  }
  decoder := json.NewDecoder(file)
  configuration := Config{}
  err = decoder.Decode(&configuration)
  if err != nil {
    return Config{}, err
  }

  if configuration.DampeningTime <= 0 {
    configuration.DampeningTime = 10
  }
  if configuration.ErrorRetryTime <= 0 {
    configuration.ErrorRetryTime = 5
  }
  if configuration.WatchdogTime <= 0 {
    configuration.WatchdogTime = 5
  }
  return configuration, nil
}

func domoticz(config Config, event Event, now time.Time) {

  if event.etype == "linedetection" && event.estate == "active" {

    fmt.Println("SENDING NOTIFICATION FOR", event, event.camera, now) 
    client := &http.Client{}
    urlstr := fmt.Sprintf("http://%s:%s/json.htm?type=command&param=switchlight&idx=%s&switchcmd=On", config.DomoticzHost, config.DomoticzPort, config.LineCrossidx)
    request, err := http.NewRequest("GET", urlstr, nil)
    if config.DomoticzBasicAuth {
	  request.SetBasicAuth(config.DomoticzUsername, config.DomoticzPassword)
	}
    fmt.Println(urlstr)
    client.Do(request)

    if err != nil {
      fmt.Println(err)
    }
  }



}


func main() {

  config, err := LoadConfig()
  if err != nil {
    fmt.Println("COULD NOT READ CONFIG", err)
    return
  }
  
  ec := make(chan Event)
  wg := &sync.WaitGroup{}
  for _, camera := range config.Cameras {
    fmt.Println("Hiknotify starting... " )
    fmt.Println("Hiknotify listening to Camera : ", config.Cameras )
    fmt.Println("Hiknotify started ..." )
    wg.Add(1)
    go GenerateEvents(wg, config, camera, ec)
  }

  type DampKey struct {
    event string
    camera *Camera
  }

  dampener := make(map[DampKey]time.Time)
  for {
    select {

      case event := <-ec:
        key := DampKey{event.etype, event.camera}
        last, ok := dampener[key]
        now := time.Now()
        if !ok || now.After(last.Add(config.DampeningTime * time.Second)) {
          domoticz(config, event, now)
          dampener[key] = now
        } else {
          fmt.Println("TIME DAMPENED ", event, key)
          dampener[key] = time.Now()
        }
        break;
    }
  }

  wg.Wait()
}
config.json

Code: Select all

{
 "Cameras": [
  {"Url": "http://ipaddress_cam/ISAPI/Event/notification/alertStream", 
   "Name": "your CameraName", 
   "Username": "username_cam", 
   "Password": "password_cam"}
],


"DampeningTime": 10,
"WatchdogTime": 10,
"ErrorRetryTime": 5,
"DomoticzHost": "ipaddress_Rpi",
"DomoticzPort": "8080",
"DomoticzBasicAuth": true,
"DomoticzUsername": "username_domo",
"DomoticzPassword": "password_domo",
"LineCrossidx": "idx_domo"
}
next you can build the script:

Code: Select all

pi@Domoticz:~/domoticz/scripts/ipcamera $ go build -o hiknotify
its time to test:

Code: Select all

pi@Domoticz:~/domoticz/scripts/ipcamera $ ./hiknotify
at least the script for autostart:
hiknotify.sh

Code: Select all

#! /bin/sh
### BEGIN INIT INFO
# Provides:          hiknotify
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Service to connect to Hikvision Camera
# Description:       Service to connect to Hikvision Camera
### END INIT INFO

case "$1" in
  start)
    echo "Start Hiknotify Service"
    # run application you want to start
    ./home/pi/domoticz/scripts/ipcamera/hiknotify &
    ;;
  stop)
    echo "Stopping Hiknotify Service"
    # kill application you want to stop
    killall hiknotify
    ;;
  *)
    echo "Usage: /etc/init.d/lgac_server{start|stop}"
    exit 1
    ;;
esac
 
exit 0
and

Code: Select all

pi@Domoticz:~/domoticz/scripts/ipcamera $ sudo cp hiknotify.sh /etc/init.d
pi@Domoticz:~/domoticz/scripts/ipcamera $ sudo chmod +x /etc/init.d/hiknotify.sh
pi@Domoticz:~/domoticz/scripts/ipcamera $ sudo update-rc.d hiknotify.sh defaults
acoustic
Posts: 1
Joined: Sunday 12 December 2021 18:57
Target OS: Linux
Domoticz version:
Contact:

Re: Hikvision Camera Linecrossing detection

Post by acoustic »

Hi Andyyyy,

Could you point me in the right direction for getting this script to notify Domoticz from multiple Hikvision cameras to their respective IDX's?

I've been enjoying your efforts with this for quite some time, so a thank is in its place!

Cheers,

acoustic
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests