longan vor 2 Jahren
Commit
3fa20a770e

+ 148 - 0
client.go

@@ -0,0 +1,148 @@
+package isapi
+
+import (
+	"bytes"
+	"errors"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+)
+
+const (
+	contentTypeXML  = `application/xml; charset="UTF-8"`
+	contentTypeJSON = `application/json; charset="UTF-8"`
+	contentTypeHTML = `text/html`
+)
+
+type Client struct {
+	Client  *http.Client
+	BaseURL string
+}
+
+func (c *Client) Close() {
+	c.Client.CloseIdleConnections()
+}
+
+func NewClient(host, username, password string) (*Client, error) {
+	u, err := url.Parse("http://" + host)
+	if err != nil {
+		return nil, errors.New("create client error," + err.Error())
+	}
+	return &Client{
+		Client: &http.Client{
+			Transport: NewAuthTransport(username, password),
+		},
+		BaseURL: u.String(),
+	}, nil
+}
+
+func (c *Client) Do(r *http.Request) ([]byte, error) {
+	resp, err := c.Client.Do(r)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
+	return body, nil
+}
+
+func (c *Client) CommonGet(path string) (resp []byte, err error) {
+	u, err := url.Parse(c.BaseURL + path)
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.Get(u)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+func (c *Client) CommonPut(data []byte, path string) (resp []byte, err error) {
+	u, err := url.Parse(c.BaseURL + path)
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.PutXML(u, data)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+func (c *Client) CommonDel(data []byte, path string) (resp []byte, err error) {
+	u, err := url.Parse(c.BaseURL + path)
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.DeleteXML(u, data)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+func (c *Client) Get(u *url.URL) ([]byte, error) {
+	req, err := http.NewRequest("GET", u.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+	return c.Do(req)
+}
+
+func (c *Client) put(u *url.URL, contentType string, data []byte) ([]byte, error) {
+	b := bytes.NewBuffer(data)
+	req, err := http.NewRequest("PUT", u.String(), b)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", contentType)
+	return c.Do(req)
+}
+
+func (c *Client) PutXML(u *url.URL, data []byte) ([]byte, error) {
+	return c.put(u, contentTypeXML, data)
+}
+
+func (c *Client) PutJSON(u *url.URL, data []byte) ([]byte, error) {
+	return c.put(u, contentTypeJSON, data)
+}
+
+func (c *Client) post(u *url.URL, contentType string, data []byte) ([]byte, error) {
+	b := bytes.NewBuffer(data)
+	req, err := http.NewRequest("POST", u.String(), b)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", contentType)
+	return c.Do(req)
+}
+
+func (c *Client) PostXML(u *url.URL, data []byte) ([]byte, error) {
+	return c.post(u, contentTypeXML, data)
+}
+
+func (c *Client) PostJSON(u *url.URL, data []byte) ([]byte, error) {
+	return c.post(u, contentTypeJSON, data)
+}
+
+func (c *Client) delete(u *url.URL, contentType string, data []byte) ([]byte, error) {
+	b := bytes.NewBuffer(data)
+	req, err := http.NewRequest("DELETE", u.String(), b)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", contentType)
+	return c.Do(req)
+}
+
+func (c *Client) DeleteXML(u *url.URL, data []byte) ([]byte, error) {
+	return c.delete(u, contentTypeXML, data)
+}
+
+func (c *Client) DeleteJSON(u *url.URL, data []byte) ([]byte, error) {
+	return c.delete(u, contentTypeJSON, data)
+}

+ 88 - 0
digest.go

@@ -0,0 +1,88 @@
+package isapi
+
+import (
+	"crypto/md5"
+	"encoding/json"
+	"fmt"
+	"log"
+	"strings"
+)
+
+// Challenge WWW-Authorization头部的值
+type Challenge struct {
+	Realm     string
+	Domain    string
+	Nonce     string
+	Opaque    string
+	Stale     string
+	Algorithm string
+	Qop       string
+}
+
+// Response 作为Authorization头部的值
+type Response struct {
+	Username string
+	Realm    string
+	Nonce    string
+	URI      string
+	Qop      string
+	Cnonce   string
+	Nc       string
+	Response string
+}
+
+func MD5(s string) string {
+	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
+}
+
+// NewChallenge 根据WWW-Authorization的值生成Challenge
+func NewChallenge(header string) *Challenge {
+	var m = make(map[string]string, 5)
+	str := header[7:]
+	split := strings.Split(str, ",")
+	for _, v := range split {
+		s := strings.Split(v, "=")
+		k := strings.Trim(s[0], " ")
+		m[k] = strings.Trim(s[1], "\"")
+	}
+
+	// Marshall digest
+	b, err := json.Marshal(m)
+	if err != nil {
+		log.Fatalln("Error:", err)
+	}
+
+	// Unmarshall into struct
+	challenge := Challenge{}
+	if err := json.Unmarshal(b, &challenge); err != nil {
+		log.Fatalln("Error:", err)
+	}
+	return &challenge
+}
+
+// Authorize 生成 Response  #客户端需要对服务端认证时cnonce应是变化的#
+func (c *Challenge) Authorize(username, password, method, uri string) *Response {
+	// MD5(<username>:<realm>:<password>)
+	a1 := MD5(fmt.Sprintf("%s:%s:%s", username, c.Realm, password))
+
+	// MD5(<request-method>:<uri>)
+	a2 := MD5(fmt.Sprintf("%s:%s", method, uri))
+
+	// MD5(MD5(A1):<nonce>:<nc>:<cnonce>:<qop>:MD5(A2))
+	response := MD5(fmt.Sprintf("%s:%s:%s:%s:%s:%s", a1, c.Nonce, "00000001", "0a4f113b", c.Qop, a2))
+	return &Response{
+		Username: username,
+		Realm:    c.Realm,
+		Nonce:    c.Nonce,
+		URI:      uri,
+		Qop:      c.Qop,
+		Cnonce:   "0a4f113b",
+		Nc:       "00000001",
+		Response: response,
+	}
+}
+
+// 生成字符串作为Authorization的值
+func (r *Response) String() string {
+	return fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", qop=%s, nc=%s, cnonce="%s", response="%s"`, r.Username, r.Realm, r.Nonce, r.URI, r.Qop, r.Nc, r.Cnonce, r.Response)
+}

+ 8 - 0
go.mod

@@ -0,0 +1,8 @@
+module isapi
+
+go 1.20
+
+require (
+	github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
+	github.com/xhit/go-simple-mail/v2 v2.16.0 // indirect
+)

+ 4 - 0
go.sum

@@ -0,0 +1,4 @@
+github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
+github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
+github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA=
+github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=

+ 52 - 0
http.go

@@ -0,0 +1,52 @@
+package isapi
+
+import (
+	"bytes"
+	"io/ioutil"
+	"net/http"
+)
+
+// AuthTransport 实现接口http.RoundTripper,自定义RoundTripper处理认证
+type AuthTransport struct {
+	Username  string
+	Password  string
+	Transport http.RoundTripper
+}
+
+func NewAuthTransport(username, password string) *AuthTransport {
+	t := &AuthTransport{
+		Username: username,
+		Password: password,
+	}
+	t.Transport = http.DefaultTransport
+	return t
+}
+
+func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	req2 := new(http.Request)
+	*req2 = *req
+	//复制header
+	req2.Header = make(http.Header)
+	for k, s := range req.Header {
+		req2.Header[k] = s
+	}
+	// 复制body
+	if req.Body != nil {
+		buf, _ := ioutil.ReadAll(req.Body)
+		req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
+		req2.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
+	}
+	//
+	resp, err := t.Transport.RoundTrip(req)
+	if err != nil || resp.StatusCode != 401 {
+		return resp, err
+	}
+	//↓未认证逻辑-----------
+	authChal := resp.Header.Get("WWW-Authenticate")
+	c := NewChallenge(authChal)
+	authResp := c.Authorize(t.Username, t.Password, req.Method, req.URL.Path)
+	resp.Body.Close()
+	//todo nonce并未重用,可以优化
+	req2.Header.Set("Authorization", authResp.String())
+	return t.Transport.RoundTrip(req2)
+}

+ 1 - 0
isapi_common.go

@@ -0,0 +1 @@
+package isapi

+ 38 - 0
isapi_event_channelCap.go

@@ -0,0 +1,38 @@
+package isapi
+
+import (
+	"encoding/xml"
+	"github.com/sirupsen/logrus"
+)
+
+type ChannelEventCapList struct {
+	ChannelEventCap []ChannelEventCap `xml:"ChannelEventCap" json:"channelEventCap"`
+}
+
+type ChannelEventCap struct {
+	EventType struct {
+		Opt string `xml:"opt,attr" json:"opt"`
+	} `xml:"eventType" json:"eventType"`
+	ChannelID string `xml:"channelID" json:"channelID"`
+	ID        string `xml:"id" json:"ID"`
+}
+
+func (c *Client) GetAllChanEventCap() (resp ChannelEventCapList, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Event/channels/capabilities")
+	if err != nil {
+		logrus.Error("请求出错", err)
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+func (c *Client) GetOneChanEventCap() (resp ChannelEventCap, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Event/channels/1/capabilities")
+	if err != nil {
+		logrus.Error("请求出错", err)
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}

+ 44 - 0
isapi_event_httphost.go

@@ -0,0 +1,44 @@
+package isapi
+
+import (
+	"encoding/xml"
+	"github.com/sirupsen/logrus"
+)
+
+type eventType string
+
+const (
+	shelterAlarm   eventType = "shelteralarm"   //遮盖报警
+	fieldAlarm     eventType = "fielddetection" //区域入侵
+	lineAlarm      eventType = "linedetection"  //越界侦测
+	regionEntrance eventType = "regionEntrance" //进入区域侦测
+	regionExiting  eventType = "regionExiting"  //离开区域侦测
+)
+
+//todo 边缘端启动时配置一次, 提供主动配置配置接口
+
+// GetHostCap 获取监听主机参数能力
+func (c *Client) GetHostCap() ([]byte, error) {
+	return c.CommonGet("/ISAPI/Event/notification/httpHosts/capabilities")
+}
+
+// PutHost 配置单个监听主机参数
+func (c *Client) PutHost(data []byte) (info ResponseStatus, err error) {
+	resp, err := c.CommonPut(data, "/ISAPI/Event/notification/httpHosts")
+	if err != nil {
+		logrus.Error("请求出错", err)
+		return
+	}
+	err = xml.Unmarshal(resp, &info)
+	return
+}
+
+// DelHost 删除单个监听主机参数
+func (c *Client) DelHost() ([]byte, error) {
+	return c.CommonDel(nil, "/ISAPI/Event/notification/httpHosts/1")
+}
+
+// GetHost 获取单个监听主机参数
+func (c *Client) GetHost() ([]byte, error) {
+	return c.CommonGet("/ISAPI/Event/notification/httpHosts/1")
+}

+ 102 - 0
isapi_event_notification.go

@@ -0,0 +1,102 @@
+package isapi
+
+import (
+	"encoding/xml"
+	"net/url"
+)
+
+type HttpHostNotification struct {
+	ID                       string `xml:"id"`
+	URL                      string `xml:"url"`
+	ProtocolType             string `xml:"protocolType"`
+	ParameterFormatType      string `xml:"parameterFormatType"`
+	AddressingFormatType     string `xml:"addressingFormatType"`
+	IpAddress                string `xml:"ipAddress"`
+	PortNo                   string `xml:"portNo"`
+	UserName                 string `xml:"userName"`
+	HttpAuthenticationMethod string `xml:"httpAuthenticationMethod"`
+	HttpBroken               string `xml:"httpBroken"`
+}
+
+// GetOneHost 获取单个监听主机参数
+func (c *Client) GetOneHost(hostID string) (resp []byte, err error) {
+	u, err := url.Parse("/ISAPI/Event/notification/httpHosts/" + hostID + "?security=1&iv=1")
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.Get(u)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+// PutOneHost 配置单个监听主机参数
+func (c *Client) PutOneHost(hostID string, data []byte) (resp []byte, err error) {
+	u, err := url.Parse("/ISAPI/Event/notification/httpHosts/" + hostID + "?security=1&iv=1")
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.PutXML(u, data)
+	return resp, err
+}
+
+// HttpHostNotificationCap 获取监听主机参数能力
+type HttpHostNotificationCap struct {
+	HostNumber string `xml:"hostNumber"`
+	UrlLen     struct {
+		Min string `xml:"min,attr"`
+		Max string `xml:"max,attr"`
+	} `xml:"urlLen"`
+	ProtocolType struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"protocolType"`
+	ParameterFormatType struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"parameterFormatType"`
+	AddressingFormatType struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"addressingFormatType"`
+	IpAddress struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"ipAddress"`
+	PortNo struct {
+		Min string `xml:"min,attr"`
+		Max string `xml:"max,attr"`
+	} `xml:"portNo"`
+	UserNameLen struct {
+		Min string `xml:"min,attr"`
+		Max string `xml:"max,attr"`
+	} `xml:"userNameLen"`
+	PasswordLen struct {
+		Min string `xml:"min,attr"`
+		Max string `xml:"max,attr"`
+	} `xml:"passwordLen"`
+	HttpAuthenticationMethod struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"httpAuthenticationMethod"`
+	UploadImagesDataType struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"uploadImagesDataType"`
+	HttpBroken struct {
+		Opt string `xml:"opt,attr"`
+		Def string `xml:"def,attr"`
+	} `xml:"httpBroken"`
+}
+
+// GetParamHost 获取监听主机参数能力
+func (c *Client) GetParamHost() (resp *HttpHostNotification, err error) {
+	u, err := url.Parse("/ISAPI/Event/notification/httpHosts/capabilities")
+	if err != nil {
+		return nil, err
+	}
+	get, err := c.Get(u)
+	if err != nil {
+		return nil, err
+	}
+	err = xml.Unmarshal(get, &resp)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}

+ 33 - 0
isapi_event_schedule.go

@@ -0,0 +1,33 @@
+package isapi
+
+// Schedule 获取指定通道视频遮盖单个通道布防时间
+type Schedule struct {
+	ID                  string `xml:"id"`
+	EventType           string `xml:"eventType"`
+	VideoInputChannelID string `xml:"videoInputChannelID"`
+	TimeBlockList       []struct {
+		TimeBlock struct {
+			DayOfWeek string `xml:"dayOfWeek"`
+			TimeRange struct {
+				BeginTime string `xml:"beginTime"`
+				EndTime   string `xml:"endTime"`
+			} `xml:"TimeRange"`
+		} `xml:"TimeBlock"`
+	} `xml:"TimeBlockList"`
+	HolidayBlockList []struct {
+		TimeBlock struct {
+			TimeRange struct {
+				BeginTime string `xml:"beginTime"`
+				EndTime   string `xml:"endTime"`
+			} `xml:"TimeRange"`
+		} `xml:"TimeBlock"`
+	} `xml:"HolidayBlockList"`
+}
+
+func (c *Client) GetSchedule() ([]byte, error) {
+	return c.CommonGet("/ISAPI/Event/schedules/tamperDetections/tamperdetection_video1")
+}
+
+func (c *Client) PutSchedule(data []byte) (resp []byte, err error) {
+	return c.CommonPut(data, "/ISAPI/Event/schedules/tamperDetections/tamperdetection_video1")
+}

+ 58 - 0
isapi_event_tamperDetection.go

@@ -0,0 +1,58 @@
+package isapi
+
+import (
+	"net/url"
+)
+
+type RegionCoordinates struct {
+	PositionX string `xml:"positionX"`
+	PositionY string `xml:"positionY"`
+}
+
+// TamperDetectionRegionList 配置指定通道视频遮盖所有区域参数
+type TamperDetectionRegionList struct {
+	TamperDetectionRegion []struct {
+		ID                    string `xml:"id"`
+		Enabled               bool   `xml:"enabled"`
+		SensitivityLevel      int    `xml:"sensitivityLevel"`
+		RegionCoordinatesList struct {
+			RegionCoordinates []RegionCoordinates `xml:"RegionCoordinates"`
+		} `xml:"RegionCoordinatesList"`
+	} `xml:"TamperDetectionRegion"`
+}
+
+// TamperDetection 获取指定通道视频遮盖参数
+type TamperDetection struct {
+	Enabled              string `xml:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize"`
+	TampersensitivityLevel    string `xml:"tampersensitivityLevel"`
+	TamperDetectionRegionList TamperDetectionRegionList
+}
+
+// GetTamperDetection 获取指定通道视频遮盖参数
+func (c *Client) GetTamperDetection() ([]byte, error) {
+	return c.CommonGet("/ISAPI/System/Video/inputs/channels/1/tamperDetection")
+}
+
+// PutTamperDetection 配置指定通道视频遮盖参数
+func (c *Client) PutTamperDetection(data []byte) (resp []byte, err error) {
+	return c.CommonPut(data, "/ISAPI/System/Video/inputs/channels/1/tamperDetection")
+}
+
+// DelTamperDetection 清除指定通道视频遮盖参数
+func (c *Client) DelTamperDetection() (resp []byte, err error) {
+	u, err := url.Parse(c.BaseURL + "/ISAPI/System/Video/inputs/channels1/tamperDetection/regions")
+	if err != nil {
+		return nil, err
+	}
+	var data = TamperDetection{}
+	data.TamperDetectionRegionList.TamperDetectionRegion = nil
+	resp, err = c.DeleteXML(u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}

+ 30 - 0
isapi_smart_calibration.go

@@ -0,0 +1,30 @@
+package isapi
+
+// SmartCalibrationList 配置最大、最小尺寸
+type SmartCalibrationList struct {
+	SmartCalibration []struct {
+		ID         string `xml:"ID" json:"ID"`
+		FilterSize struct {
+			MinTargetSize struct {
+				RegionCoordinatesList struct {
+					RegionCoordinates []struct {
+						PositionX string `xml:"positionX" json:"positionX"`
+						PositionY string `xml:"positionY" json:"positionY"`
+					} `xml:"RegionCoordinates" json:"RegionCoordinates"`
+				} `xml:"RegionCoordinatesList" json:"RegionCoordinatesList"`
+			} `xml:"MinTargetSize" json:"MinTargetSize"`
+			MaxTargetSize struct {
+				RegionCoordinatesList struct {
+					RegionCoordinates []struct {
+						PositionX string `xml:"positionX" json:"positionX"`
+						PositionY string `xml:"positionY" json:"positionY"`
+					} `xml:"RegionCoordinates" json:"RegionCoordinates"`
+				} `xml:"RegionCoordinatesList" json:"RegionCoordinatesList"`
+			} `xml:"MaxTargetSize" json:"MaxTargetSize"`
+			Mode struct {
+				Text string `xml:",chardata" json:"chardata"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"mode" json:"mode"`
+		} `xml:"FilterSize" json:"FilterSize"`
+	} `xml:"SmartCalibration" json:"SmartCalibration"`
+}

+ 166 - 0
isapi_smart_fieldDetection.go

@@ -0,0 +1,166 @@
+package isapi
+
+import (
+	"encoding/json"
+	"encoding/xml"
+)
+
+//能力
+//http://192.168.1.64/ISAPI/Smart/FieldDetection/1/capabilities
+//http://192.168.1.64/ISAPI/Smart/channels/1/calibrations/capabilities
+
+// FieldDetectionCap 区域入侵参数能力
+type FieldDetectionCap struct {
+	ID      string `xml:"id" json:"id"`
+	Enabled struct {
+		Text string `xml:",chardata" json:"value"`
+		Opt  string `xml:"opt,attr" json:"opt"`
+	} `xml:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalized_screen_width"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalized_screen_height"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	FieldDetectionRegionList struct {
+		Size                 string `xml:"size,attr" json:"size"`
+		FieldDetectionRegion []struct {
+			ID                      string `xml:"id" json:"id"`
+			MinRegionCoordinatesNum string `xml:"minRegionCoordinatesNum" json:"minRegionCoordinatesNum"`
+			MaxRegionCoordinatesNum string `xml:"maxRegionCoordinatesNum" json:"maxRegionCoordinatesNum"`
+			SensitivityLevel        struct {
+				Text string `xml:",chardata" json:"value"`
+				Min  string `xml:"min,attr" json:"min"`
+				Max  string `xml:"max,attr" json:"max"`
+			} `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			TimeThreshold struct {
+				Text string `xml:",chardata" json:"value"`
+				Min  string `xml:"min,attr" json:"min"`
+				Max  string `xml:"max,attr" json:"max"`
+			} `xml:"timeThreshold" json:"timeThreshold"`
+			CoordinatesList struct {
+				Coordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"Coordinates" json:"Coordinates"`
+			} `xml:"CoordinatesList" json:"CoordinatesList"`
+			DetectionTarget struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+				Def  string `xml:"def,attr" json:"def"`
+			} `xml:"alarmConfidence" json:"alarmConfidence"`
+		} `xml:"FieldDetectionRegion" json:"FieldDetectionRegion"`
+	} `xml:"FieldDetectionRegionList" json:"FieldDetectionRegionList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter" json:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter" json:"isSupportVehicleMisinfoFilter"`
+	IsSupportTargetMultiSelect    string `xml:"isSupportTargetMultiSelect" json:"isSupportTargetMultiSelect"`
+	IsSupportAllDayUpload         string `xml:"isSupportAllDayUpload" json:"isSupportAllDayUpload"`
+}
+
+func (c *Client) GetFieldDetectionCap() (resp FieldDetectionCap, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/FieldDetection/1/capabilities")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	detection, _ := c.GetFieldDetection()
+	for i, v := range detection.FieldDetectionRegionList.FieldDetectionRegion {
+		resp.FieldDetectionRegionList.FieldDetectionRegion[i].AlarmConfidence.Text = v.AlarmConfidence
+	}
+	return
+}
+
+func (c *Client) GetSizeFd() (resp SmartCalibrationList, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/channels/1/calibrations/FieldDetection")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+func (c *Client) PutSizeFd(data []byte) (resp ResponseStatus, err error) {
+	var info SmartCalibrationList
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/channels/1/calibrations/FieldDetection")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+// PutFieldDetection 设置区域入侵报警区域
+func (c *Client) PutFieldDetection(data []byte) (resp ResponseStatus, err error) {
+	var info FieldDetectionParam
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/FieldDetection/1")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+// GetFieldDetection 获取报警区域
+func (c *Client) GetFieldDetection() (resp FieldDetectionParam, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/FieldDetection/1")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+// FieldDetectionParam 查询,配置 进入区域参数
+type FieldDetectionParam struct {
+	ID                   string `xml:"id" json:"id"`
+	Enabled              string `xml:"enabled" json:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	FieldDetectionRegionList struct {
+		Size                 string `xml:"size,attr" json:"size"`
+		FieldDetectionRegion []struct {
+			ID                    string `xml:"id" json:"id"`
+			Enabled               string `xml:"enabled" json:"enabled"`
+			SensitivityLevel      string `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			TimeThreshold         string `xml:"timeThreshold" json:"timeThreshold"`
+			DetectionTarget       string `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence       string `xml:"alarmConfidence"json:"alarmConfidence"`
+			RegionCoordinatesList struct {
+				RegionCoordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"RegionCoordinates" json:"RegionCoordinates"`
+			} `xml:"RegionCoordinatesList" json:"RegionCoordinatesList"`
+		} `xml:"FieldDetectionRegion" json:"FieldDetectionRegion"`
+	} `xml:"FieldDetectionRegionList" json:"FieldDetectionRegionList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter" json:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter" json:"isSupportVehicleMisinfoFilter"`
+}

+ 166 - 0
isapi_smart_lineDetection.go

@@ -0,0 +1,166 @@
+package isapi
+
+import (
+	"encoding/json"
+	"encoding/xml"
+)
+
+//能力
+//http://192.168.1.64/ISAPI/Smart/LineDetection/1/capabilities
+//http://192.168.1.64/ISAPI/Smart/channels/1/calibrations/capabilities
+
+// LineDetectionParam 越界侦测
+type LineDetectionParam struct {
+	ID                   string `xml:"id" json:"id"`
+	Enabled              string `xml:"enabled" json:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	LineItemList struct {
+		Size     string `xml:"size,attr" json:"size"`
+		LineItem []struct {
+			ID                   string `xml:"id" json:"id"`
+			Enabled              string `xml:"enabled" json:"enabled"`
+			SensitivityLevel     string `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			DirectionSensitivity string `xml:"directionSensitivity"json:"directionSensitivity"`
+			DetectionTarget      string `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence      string `xml:"alarmConfidence" json:"alarmConfidence"`
+			CoordinatesList      struct {
+				Coordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"Coordinates" json:"Coordinates"`
+			} `xml:"CoordinatesList" json:"CoordinatesList"`
+		} `xml:"LineItem" json:"LineItem"`
+	} `xml:"LineItemList" json:"LineItemList"`
+	IsSupportMultiScene string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	RecogRuleType       string `xml:"recogRuleType" json:"recogRuleType"`
+}
+
+func (c *Client) GetLineDetectionCap() (resp LineDetectionCap, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/LineDetection/1/capabilities")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	detection, _ := c.GetLineDetection()
+	for i, v := range detection.LineItemList.LineItem {
+		resp.LineItemList.LineItem[i].AlarmConfidence.Text = v.AlarmConfidence
+	}
+	return
+}
+
+func (c *Client) GetSizeLd() (resp SmartCalibrationList, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/channels/1/calibrations/linedetection")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+func (c *Client) PutSizeLd(data []byte) (resp ResponseStatus, err error) {
+	var info SmartCalibrationList
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/channels/1/calibrations/linedetection")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+// GetLineDetection 获取单个通道越界侦测规则
+func (c *Client) GetLineDetection() (resp LineDetectionParam, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/LineDetection/1")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+// PutLineDetection 配置单个通道越界侦测规则
+func (c *Client) PutLineDetection(data []byte) (resp ResponseStatus, err error) {
+	var info LineDetectionParam
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/LineDetection/1")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+type LineDetectionCap struct {
+	ID      string `xml:"id" json:"id"`
+	Enabled struct {
+		Text string `xml:",chardata" json:"value"`
+		Opt  string `xml:"opt,attr" json:"opt"`
+	} `xml:"enabled" json:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	LineItemList struct {
+		Size     string `xml:"size,attr" json:"size"`
+		LineItem []struct {
+			ID      string `xml:"id" json:"id"`
+			Enabled struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"enabled" json:"enabled"`
+			SensitivityLevel struct {
+				Text string `xml:",chardata" json:"value"`
+				Min  string `xml:"min,attr" json:"min"`
+				Max  string `xml:"max,attr" json:"max"`
+			} `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			DirectionSensitivity struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"directionSensitivity" json:"directionSensitivity"`
+			CoordinatesList struct {
+				Coordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"Coordinates" json:"Coordinates"`
+			} `xml:"CoordinatesList" json:"CoordinatesList"`
+			DetectionTarget struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+				Def  string `xml:"def,attr" json:"def"`
+			} `xml:"alarmConfidence" json:"alarmConfidence"`
+		} `xml:"LineItem" json:"LineItem"`
+	} `xml:"LineItemList" json:"LineItemList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	RecogRuleType                 string `xml:"recogRuleType" json:"recogRuleType"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter" json:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter" json:"isSupportVehicleMisinfoFilter"`
+	IsSupportTargetMultiSelect    string `xml:"isSupportTargetMultiSelect" json:"isSupportTargetMultiSelect"`
+	IsSupportAllDayUpload         string `xml:"isSupportAllDayUpload" json:"isSupportAllDayUpload"`
+}

+ 155 - 0
isapi_smart_regionEntrance.go

@@ -0,0 +1,155 @@
+package isapi
+
+import (
+	"encoding/json"
+	"encoding/xml"
+)
+
+// RegionEntranceParam 进入区域
+type RegionEntranceParam struct {
+	ID                   string `xml:"id" json:"id"`
+	Enabled              string `xml:"enabled" json:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	RegionEntranceRegionList struct {
+		Size                 string `xml:"size,attr" json:"size"`
+		RegionEntranceRegion []struct {
+			ID                    string `xml:"id" json:"id"`
+			SensitivityLevel      string `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			DetectionTarget       string `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence       string `xml:"alarmConfidence" json:"alarmConfidence"`
+			RegionCoordinatesList struct {
+				RegionCoordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"RegionCoordinates" json:"RegionCoordinates"`
+			} `xml:"RegionCoordinatesList" json:"RegionCoordinatesList"`
+		} `xml:"RegionEntranceRegion" json:"RegionEntranceRegion"`
+	} `xml:"RegionEntranceRegionList" json:"RegionEntranceRegionList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter" json:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter" json:"isSupportVehicleMisinfoFilter"`
+	IsSupportTargetMultiSelect    string `xml:"isSupportTargetMultiSelect" json:"isSupportTargetMultiSelect"`
+}
+
+func (c *Client) GetRegionEntranceCap() (resp RegionEntranceCap, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/regionEntrance/1/capabilities")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	detection, _ := c.GetRegionEntrance()
+	for i, v := range detection.RegionEntranceRegionList.RegionEntranceRegion {
+		resp.RegionEntranceRegionList.RegionEntranceRegion[i].AlarmConfidence.Text = v.AlarmConfidence
+	}
+	return
+}
+
+func (c *Client) GetSizeRe() (resp SmartCalibrationList, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/channels/1/calibrations/regionEntrance")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+func (c *Client) PutSizeRe(data []byte) (resp ResponseStatus, err error) {
+	var info SmartCalibrationList
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/channels/1/calibrations/regionEntrance")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+// GetRegionEntrance 获取区域侦测参数
+func (c *Client) GetRegionEntrance() (resp RegionEntranceParam, err error) {
+	bytes, err := c.CommonGet("/ISAPI/Smart/regionEntrance/1")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+// PutRegionEntrance 配置区域侦测参数
+func (c *Client) PutRegionEntrance(data []byte) (resp ResponseStatus, err error) {
+	var info RegionEntranceParam
+	err = json.Unmarshal(data, &info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	marshal, err := xml.Marshal(info)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	respData, err := c.CommonPut(marshal, "/ISAPI/Smart/regionEntrance/1")
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	err = xml.Unmarshal(respData, &resp)
+	if err != nil {
+		return ResponseStatus{}, err
+	}
+	return
+}
+
+type RegionEntranceCap struct {
+	ID      string `xml:"id"`
+	Enabled struct {
+		Text string `xml:",chardata" json:"value"`
+		Opt  string `xml:"opt,attr" json:"opt"`
+	} `xml:"enabled" json:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth" json:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight" json:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize" json:"normalizedScreenSize"`
+	RegionEntranceRegionList struct {
+		Size                 string `xml:"size,attr" json:"size"`
+		RegionEntranceRegion []struct {
+			ID               string `xml:"id" json:"id"`
+			SensitivityLevel struct {
+				Text string `xml:",chardata" json:"value"`
+				Min  string `xml:"min,attr" json:"min"`
+				Max  string `xml:"max,attr" json:"max"`
+			} `xml:"sensitivityLevel" json:"sensitivityLevel"`
+			RegionCoordinatesList struct {
+				RegionCoordinates []struct {
+					PositionX string `xml:"positionX" json:"positionX"`
+					PositionY string `xml:"positionY" json:"positionY"`
+				} `xml:"RegionCoordinates" json:"RegionCoordinates"`
+			} `xml:"RegionCoordinatesList" json:"RegionCoordinatesList"`
+			MinRegionCoordinatesNum string `xml:"minRegionCoordinatesNum" json:"minRegionCoordinatesNum"`
+			MaxRegionCoordinatesNum string `xml:"maxRegionCoordinatesNum" json:"maxRegionCoordinatesNum"`
+			DetectionTarget         struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+			} `xml:"detectionTarget" json:"detectionTarget"`
+			AlarmConfidence struct {
+				Text string `xml:",chardata" json:"value"`
+				Opt  string `xml:"opt,attr" json:"opt"`
+				Def  string `xml:"def,attr" json:"def"`
+			} `xml:"alarmConfidence" json:"alarmConfidence"`
+		} `xml:"RegionEntranceRegion" json:"RegionEntranceRegion"`
+	} `xml:"RegionEntranceRegionList" json:"RegionEntranceRegionList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene" json:"isSupportMultiScene"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter" json:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter" json:"isSupportVehicleMisinfoFilter"`
+	IsSupportTargetMultiSelect    string `xml:"isSupportTargetMultiSelect" json:"isSupportTargetMultiSelect"`
+	IsSupportAllDayUpload         string `xml:"isSupportAllDayUpload" json:"isSupportAllDayUpload"`
+}

+ 33 - 0
isapi_smart_regionExiting.go

@@ -0,0 +1,33 @@
+package isapi
+
+type RegionExiting struct {
+	ID                   string `xml:"id"`
+	Enabled              string `xml:"enabled"`
+	NormalizedScreenSize struct {
+		NormalizedScreenWidth  string `xml:"normalizedScreenWidth"`
+		NormalizedScreenHeight string `xml:"normalizedScreenHeight"`
+	} `xml:"normalizedScreenSize"`
+	RegionExitingRegionList struct {
+		Size                string `xml:"size,attr"`
+		RegionExitingRegion []struct {
+			ID                    string `xml:"id"`
+			SensitivityLevel      string `xml:"sensitivityLevel"`
+			RegionCoordinatesList string `xml:"RegionCoordinatesList"`
+			DetectionTarget       string `xml:"detectionTarget"`
+			AlarmConfidence       struct {
+				Opt string `xml:"opt,attr"`
+			} `xml:"alarmConfidence"`
+		} `xml:"RegionExitingRegion"`
+	} `xml:"RegionExitingRegionList"`
+	IsSupportMultiScene           string `xml:"isSupportMultiScene"`
+	IsSupportHumanMisinfoFilter   string `xml:"isSupportHumanMisinfoFilter"`
+	IsSupportVehicleMisinfoFilter string `xml:"isSupportVehicleMisinfoFilter"`
+	IsSupportTargetMultiSelect    string `xml:"isSupportTargetMultiSelect"`
+}
+
+func (c *Client) GetRegionExiting() ([]byte, error) {
+	return c.CommonGet("/ISAPI/Smart/regionExiting/1")
+}
+func (c *Client) PutRegionExiting(data []byte) ([]byte, error) {
+	return c.CommonPut(data, "/ISAPI/Smart/regionExiting/1")
+}

+ 328 - 0
isapi_system_deviceCap.go

@@ -0,0 +1,328 @@
+package isapi
+
+import (
+	"encoding/xml"
+)
+
+// DeviceCap 获取系统能力
+type DeviceCap struct {
+	XMLName xml.Name `xml:"DeviceCap"`
+	Text    string   `xml:",chardata"`
+	Version string   `xml:"version,attr"`
+	Xmlns   string   `xml:"xmlns,attr"`
+	SysCap  struct {
+		IsSupportDst string `xml:"isSupportDst"`
+		NetworkCap   struct {
+			IsSupportWireless string `xml:"isSupportWireless"`
+			IsSupportPPPoE    string `xml:"isSupportPPPoE"`
+			IsSupportBond     string `xml:"isSupportBond"`
+			IsSupport8021x    string `xml:"isSupport802_1x"`
+			IsSupportNtp      string `xml:"isSupportNtp"`
+			IsSupportFtp      string `xml:"isSupportFtp"`
+			IsSupportUpnp     string `xml:"isSupportUpnp"`
+			IsSupportDdns     string `xml:"isSupportDdns"`
+			IsSupportHttps    string `xml:"isSupportHttps"`
+			SnmpCap           struct {
+				IsSupport string `xml:"isSupport"`
+			} `xml:"SnmpCap"`
+			IsSupportExtNetCfg                string `xml:"isSupportExtNetCfg"`
+			IsSupportIPFilter                 string `xml:"isSupportIPFilter"`
+			IsSupportEZVIZ                    string `xml:"isSupportEZVIZ"`
+			IsSupportEhome                    string `xml:"isSupportEhome"`
+			IsSupportWirelessDial             string `xml:"isSupportWirelessDial"`
+			IsSupportWirelessServer           string `xml:"isSupportWirelessServer"`
+			IsSupportWPS                      string `xml:"isSupportWPS"`
+			IsWirelessMutexWithWirelessServer string `xml:"isWirelessMutexWithWirelessServer"`
+			IsSupportMACFilter                string `xml:"isSupportMACFilter"`
+			IsSupportRFIDData                 string `xml:"isSupportRFIDData"`
+			IsSupportwifiProbeSSID            string `xml:"isSupportwifiProbeSSID"`
+			IsSupportWifiProbe                string `xml:"isSupportWifiProbe"`
+			VerificationCode                  struct {
+				Min string `xml:"min,attr"`
+				Max string `xml:"max,attr"`
+			} `xml:"verificationCode"`
+			VerificationCodeModification struct {
+				VerificationCodeType struct {
+					Opt string `xml:"opt,attr"`
+				} `xml:"verificationCodeType"`
+				IsSupportDeclarationURL   string `xml:"isSupportDeclarationURL"`
+				IsSupportPrivacyPolicyURL string `xml:"isSupportPrivacyPolicyURL"`
+				VerificationCodeModify    struct {
+					Opt string `xml:"opt,attr"`
+				} `xml:"verificationCodeModify"`
+			} `xml:"VerificationCodeModification"`
+			IsSupportIntegrate       string `xml:"isSupportIntegrate"`
+			IsSupportPlatformAccess  string `xml:"isSupportPlatformAccess"`
+			IsSupportGetLinkSocketIP string `xml:"isSupportGetLinkSocketIP"`
+			IsSupportWebSocket       string `xml:"isSupportWebSocket"`
+			IsSupportWebSocketS      string `xml:"isSupportWebSocketS"`
+			IsSupportVideoImgDB      string `xml:"isSupportVideoImgDB"`
+			IsSupportDynamicHostName string `xml:"isSupportDynamicHostName"`
+			IsSupportEmailEncrypt    string `xml:"isSupportEmailEncrypt"`
+			IsSupportEZVIZUnbind     string `xml:"isSupportEZVIZUnbind"`
+		} `xml:"NetworkCap"`
+		IOCap struct {
+			IsSupportStrobeLamp string `xml:"isSupportStrobeLamp"`
+		} `xml:"IOCap"`
+		SerialCap struct {
+			Rs485PortNums      string `xml:"rs485PortNums"`
+			SupportRS232Config string `xml:"supportRS232Config"`
+			Rs422PortNums      string `xml:"rs422PortNums"`
+			Rs232PortNums      string `xml:"rs232PortNums"`
+		} `xml:"SerialCap"`
+		VideoCap struct {
+			VideoInputPortNums              string `xml:"videoInputPortNums"`
+			VideoOutputPortNums             string `xml:"videoOutputPortNums"`
+			IsSupportHeatmap                string `xml:"isSupportHeatmap"`
+			IsSupportCounting               string `xml:"isSupportCounting"`
+			IsSupportPicture                string `xml:"isSupportPicture"`
+			IsSupportPrivacyMask            string `xml:"isSupportPrivacyMask"`
+			IsSupportBinocularPreviewSwitch string `xml:"isSupportBinocularPreviewSwitch"`
+			IsSupportCalibCheck             string `xml:"isSupportCalibCheck"`
+			IsSupportPIP                    string `xml:"isSupportPIP"`
+			IsSupportVideoOutputMode        string `xml:"isSupportVideoOutputMode"`
+		} `xml:"VideoCap"`
+		AudioCap struct {
+			AudioInputNums  string `xml:"audioInputNums"`
+			AudioOutputNums string `xml:"audioOutputNums"`
+		} `xml:"AudioCap"`
+		IsSupportExternalDevice string `xml:"isSupportExternalDevice"`
+		IsSupportSubscribeEvent string `xml:"isSupportSubscribeEvent"`
+		IsSupportDiagnosedData  string `xml:"isSupportDiagnosedData"`
+		IsSupportMetadata       string `xml:"isSupportMetadata"`
+	} `xml:"SysCap"`
+	VoicetalkNums     string `xml:"voicetalkNums"`
+	IsSupportSnapshot string `xml:"isSupportSnapshot"`
+	SecurityCap       struct {
+		SupportUserNums           string `xml:"supportUserNums"`
+		UserBondIpNums            string `xml:"userBondIpNums"`
+		UserBondMacNums           string `xml:"userBondMacNums"`
+		IsSupCertificate          string `xml:"isSupCertificate"`
+		IssupIllegalLoginLock     string `xml:"issupIllegalLoginLock"`
+		IsSupportOnlineUser       string `xml:"isSupportOnlineUser"`
+		IsSupportAnonymous        string `xml:"isSupportAnonymous"`
+		IsSupportStreamEncryption string `xml:"isSupportStreamEncryption"`
+		SecurityVersion           struct {
+			Opt string `xml:"opt,attr"`
+		} `xml:"securityVersion"`
+		KeyIterateNum                   string `xml:"keyIterateNum"`
+		IsSupportUserCheck              string `xml:"isSupportUserCheck"`
+		IsSupportSecurityQuestionConfig string `xml:"isSupportSecurityQuestionConfig"`
+		SupportSecurityNode             struct {
+			Opt string `xml:"opt,attr"`
+		} `xml:"supportSecurityNode"`
+		SecurityLimits struct {
+			LoginPasswordLenLimit struct {
+				Min string `xml:"min,attr"`
+				Max string `xml:"max,attr"`
+			} `xml:"LoginPasswordLenLimit"`
+			SecurityAnswerLenLimit struct {
+				Min string `xml:"min,attr"`
+				Max string `xml:"max,attr"`
+			} `xml:"SecurityAnswerLenLimit"`
+		} `xml:"SecurityLimits"`
+		RSAKeyLength struct {
+			Opt string `xml:"opt,attr"`
+			Def string `xml:"def,attr"`
+		} `xml:"RSAKeyLength"`
+		IsSupportONVIFUserManagement       string `xml:"isSupportONVIFUserManagement"`
+		IsSupportGB35114Certificate        string `xml:"isSupportGB35114Certificate"`
+		IsSupportSIPCertificatesManagement string `xml:"isSupportSIPCertificatesManagement"`
+		WebCertificateCap                  struct {
+			CertificateType struct {
+				Opt string `xml:"opt,attr"`
+			} `xml:"CertificateType"`
+			SecurityAlgorithm struct {
+				AlgorithmType struct {
+					Opt string `xml:"opt,attr"`
+				} `xml:"algorithmType"`
+			} `xml:"SecurityAlgorithm"`
+		} `xml:"WebCertificateCap"`
+		IsSupportConfigFileImport string `xml:"isSupportConfigFileImport"`
+		IsSupportConfigFileExport string `xml:"isSupportConfigFileExport"`
+		CfgFileSecretKeyLenLimit  struct {
+			Min string `xml:"min,attr"`
+			Max string `xml:"max,attr"`
+		} `xml:"cfgFileSecretKeyLenLimit"`
+		IsIrreversible                        string `xml:"isIrreversible"`
+		Salt                                  string `xml:"salt"`
+		IsSupportOnvifInfo                    string `xml:"isSupportOnvifInfo"`
+		IsSupportDeviceCertificatesManagement string `xml:"isSupportDeviceCertificatesManagement"`
+		IsSupportDeviceSelfSignCertExport     string `xml:"isSupportDeviceSelfSignCertExport"`
+		IsSupportSecurityEmail                string `xml:"isSupportSecurityEmail"`
+		MaxIllegalLoginTimes                  struct {
+			Min string `xml:"min,attr"`
+			Max string `xml:"max,attr"`
+			Def string `xml:"def,attr"`
+		} `xml:"maxIllegalLoginTimes"`
+		SecurityAdvanced struct {
+			NoOperationEnabled string `xml:"noOperationEnabled"`
+			NoOperationTime    struct {
+				Min string `xml:"min,attr"`
+				Max string `xml:"max,attr"`
+				Def string `xml:"def,attr"`
+			} `xml:"noOperationTime"`
+		} `xml:"SecurityAdvanced"`
+		LoginLinkNum struct {
+			MaxLinkNum struct {
+				Min string `xml:"min,attr"`
+				Max string `xml:"max,attr"`
+				Def string `xml:"def,attr"`
+			} `xml:"maxLinkNum"`
+		} `xml:"LoginLinkNum"`
+		IsSupportCertificateCustomID string `xml:"isSupportCertificateCustomID"`
+		IsSupportEncryptCertificate  string `xml:"isSupportEncryptCertificate"`
+		MaxIllegalLoginLockTime      struct {
+			Min string `xml:"min,attr"`
+			Max string `xml:"max,attr"`
+			Def string `xml:"def,attr"`
+		} `xml:"maxIllegalLoginLockTime"`
+		IsSupportSoftwareLicense string `xml:"isSupportSoftwareLicense"`
+	} `xml:"SecurityCap"`
+	EventCap struct {
+		IsSupportHDFull                 string `xml:"isSupportHDFull"`
+		IsSupportHDError                string `xml:"isSupportHDError"`
+		IsSupportNicBroken              string `xml:"isSupportNicBroken"`
+		IsSupportIpConflict             string `xml:"isSupportIpConflict"`
+		IsSupportIllAccess              string `xml:"isSupportIllAccess"`
+		IsSupportViException            string `xml:"isSupportViException"`
+		IsSupportViMismatch             string `xml:"isSupportViMismatch"`
+		IsSupportRecordException        string `xml:"isSupportRecordException"`
+		IsSupportTriggerFocus           string `xml:"isSupportTriggerFocus"`
+		IsSupportMotionDetection        string `xml:"isSupportMotionDetection"`
+		IsSupportVideoLoss              string `xml:"isSupportVideoLoss"`
+		IsSupportTamperDetection        string `xml:"isSupportTamperDetection"`
+		IsSupportStudentsStoodUp        string `xml:"isSupportStudentsStoodUp"`
+		IsSupportFramesPeopleCounting   string `xml:"isSupportFramesPeopleCounting"`
+		IsSupportPersonQueueDetection   string `xml:"isSupportPersonQueueDetection"`
+		IsSupportFaceContrast           string `xml:"isSupportFaceContrast"`
+		IsSupportFaceLib                string `xml:"isSupportFaceLib"`
+		IsSupportFaceSnap               string `xml:"isSupportFaceSnap"`
+		IsSupportPersonDensityDetection string `xml:"isSupportPersonDensityDetection"`
+		IsSupportTeacherBehaviorDetect  string `xml:"isSupportTeacherBehaviorDetect"`
+		IsSupportCityManagement         string `xml:"isSupportCityManagement"`
+		IsSupportMixedTargetDetection   string `xml:"isSupportMixedTargetDetection"`
+		IsSupportFaceSnapModeling       string `xml:"isSupportFaceSnapModeling"`
+		IsSupportIntersectionAnalysis   string `xml:"isSupportIntersectionAnalysis"`
+		IsSupportLuma                   string `xml:"isSupportLuma"`
+		IsSupportChroma                 string `xml:"isSupportChroma"`
+		IsSupportSnow                   string `xml:"isSupportSnow"`
+		IsSupportStreak                 string `xml:"isSupportStreak"`
+		IsSupportFreeze                 string `xml:"isSupportFreeze"`
+		IsSupportSigLose                string `xml:"isSupportSigLose"`
+		IsSupportClarity                string `xml:"isSupportClarity"`
+		IsSupportJitter                 string `xml:"isSupportJitter"`
+		IsSupportBlock                  string `xml:"isSupportBlock"`
+		IsSupportFlowers                string `xml:"isSupportFlowers"`
+		IsSupportNoise                  string `xml:"isSupportNoise"`
+		IsSupportGhost                  string `xml:"isSupportGhost"`
+		IsSupportPurple                 string `xml:"isSupportPurple"`
+		IsSupportICR                    string `xml:"isSupportICR"`
+		IsSupportProtectiveFilm         string `xml:"isSupportProtectiveFilm"`
+	} `xml:"EventCap"`
+	RacmCap struct {
+		NasNums           string `xml:"nasNums"`
+		PictureSearchType struct {
+			Opt string `xml:"opt,attr"`
+		} `xml:"pictureSearchType"`
+		RecordSearchType struct {
+			Opt string `xml:"opt,attr"`
+		} `xml:"recordSearchType"`
+		SecurityLog struct {
+			IsSupportSecurityLog   string `xml:"isSupportSecurityLog"`
+			IsSupportLogServer     string `xml:"isSupportLogServer"`
+			IsSupportLogServerTest string `xml:"isSupportLogServerTest"`
+			SecurityLogTypeList    struct {
+				SecurityLogType []struct {
+					PrimaryType   string `xml:"primaryType"`
+					SecondaryType struct {
+						Opt string `xml:"opt,attr"`
+					} `xml:"secondaryType"`
+				} `xml:"SecurityLogType"`
+			} `xml:"SecurityLogTypeList"`
+		} `xml:"SecurityLog"`
+		IsSupportRacmChannelsCap struct {
+			Opt string `xml:"opt,attr"`
+		} `xml:"isSupportRacmChannelsCap"`
+	} `xml:"RacmCap"`
+	SmartCap struct {
+		IsSupportROI                  string `xml:"isSupportROI"`
+		IsSupportAudioDetection       string `xml:"isSupportAudioDetection"`
+		IsSupportFaceDetect           string `xml:"isSupportFaceDetect"`
+		IsSupportLineDetection        string `xml:"isSupportLineDetection"`
+		IsSupportFieldDetection       string `xml:"isSupportFieldDetection"`
+		IsSupportRegionEntrance       string `xml:"isSupportRegionEntrance"`
+		IsSupportRegionExiting        string `xml:"isSupportRegionExiting"`
+		IsSupportLoitering            string `xml:"isSupportLoitering"`
+		IsSupportGroup                string `xml:"isSupportGroup"`
+		IsSupportRapidMove            string `xml:"isSupportRapidMove"`
+		IsSupportParking              string `xml:"isSupportParking"`
+		IsSupportUnattendedBaggage    string `xml:"isSupportUnattendedBaggage"`
+		IsSupportAttendedBaggage      string `xml:"isSupportAttendedBaggage"`
+		IsSupportSmartCalibration     string `xml:"isSupportSmartCalibration"`
+		IsSupportIntelliTrace         string `xml:"isSupportIntelliTrace"`
+		IsSupportPeopleDetection      string `xml:"isSupportPeopleDetection"`
+		IsSupportDefocusDetection     string `xml:"isSupportDefocusDetection"`
+		IsSupportSceneChangeDetection string `xml:"isSupportSceneChangeDetection"`
+		IsSupportStorageDetection     string `xml:"isSupportStorageDetection"`
+		IsSupportChannelResource      string `xml:"isSupportChannelResource"`
+	} `xml:"SmartCap"`
+	WLAlarmCap struct {
+		IsSupportTeleControl string `xml:"isSupportTeleControl"`
+		IsSupportPIR         string `xml:"isSupportPIR"`
+		IsSupportWLSensors   string `xml:"isSupportWLSensors"`
+		IsSupportCallHelp    string `xml:"isSupportCallHelp"`
+		WLSensorsNum         string `xml:"WLSensorsNum"`
+	} `xml:"WLAlarmCap"`
+	IsSupportGIS              string `xml:"isSupportGIS"`
+	IsSupportCompass          string `xml:"isSupportCompass"`
+	IsSupportRoadInfoOverlays string `xml:"isSupportRoadInfoOverlays"`
+	TestCap                   struct {
+		IsSupportFTPTest   string `xml:"isSupportFTPTest"`
+		IsSupportPingTest  string `xml:"isSupportPingTest"`
+		IsSupportNTPTest   string `xml:"isSupportNTPTest"`
+		IsSupportNASTest   string `xml:"isSupportNASTest"`
+		IsSupportEmailTest string `xml:"isSupportEmailTest"`
+	} `xml:"TestCap"`
+	PanoramaCap struct {
+		IsSupportGeneratePanorama   string `xml:"isSupportGeneratePanorama"`
+		IsSupportPanoramaPosition3D string `xml:"isSupportPanoramaPosition3D"`
+		IsSupportPreset             string `xml:"isSupportPreset"`
+	} `xml:"PanoramaCap"`
+	IsSupportFaceCaptureStatistics string `xml:"isSupportFaceCaptureStatistics"`
+	IsSupportElectronicsEnlarge    string `xml:"isSupportElectronicsEnlarge"`
+	IsSupportTraffic               string `xml:"isSupportTraffic"`
+	IsSupportFirmwareVersionInfo   string `xml:"isSupportFirmwareVersionInfo"`
+	IsSupportLaserSpotManual       string `xml:"isSupportLaserSpotManual"`
+	IsSupportSetupCalibration      string `xml:"isSupportSetupCalibration"`
+	IsSupportPicInfoOverlap        string `xml:"isSupportPicInfoOverlap"`
+	IsOnlySupportAnalogChannel     string `xml:"isOnlySupportAnalogChannel"`
+	IsSupportChannelEventCap       string `xml:"isSupportChannelEventCap"`
+	IsSupportChannelEventListCap   string `xml:"isSupportChannelEventListCap"`
+	VCAResourceChannelsCap         struct {
+		ChannelsList struct {
+			ChannelsID string `xml:"channelsID"`
+		} `xml:"ChannelsList"`
+	} `xml:"VCAResourceChannelsCap"`
+	SupportSnapshotChannel struct {
+		Opt string `xml:"opt,attr"`
+	} `xml:"supportSnapshotChannel"`
+	IsSupportGPSCalibratation     string `xml:"isSupportGPSCalibratation"`
+	IsSupportGPSLabelTracking     string `xml:"isSupportGPSLabelTracking"`
+	IsSupportCalibrationStream    string `xml:"isSupportCalibrationStream"`
+	IsSupportActiveMulticast      string `xml:"isSupportActiveMulticast"`
+	IsSupportChannelFullEventCap  string `xml:"isSupportChannelFullEventCap"`
+	IsSupportAUXInfoCap           string `xml:"isSupportAUXInfoCap"`
+	IsSupportVehicleMonitor       string `xml:"isSupportVehicleMonitor"`
+	IsSupportManualVehicleMonitor string `xml:"isSupportManualVehicleMonitor"`
+	IsSupportSnapshotAsync        string `xml:"isSupportSnapshotAsync"`
+	IsSupportAutoMaintenance      string `xml:"isSupportAutoMaintenance"`
+	IsSupportSIMCardStatus        string `xml:"isSupportSIMCardStatus"`
+	IsSupportISUPHttpPassthrough  string `xml:"isSupportISUPHttpPassthrough"`
+	IsSupportTOFShelterAlarm      string `xml:"isSupportTOFShelterAlarm"`
+	IsSupportT1Test               string `xml:"isSupportT1Test"`
+}
+
+func (c *Client) GetSystemCap() ([]byte, error) {
+	return c.CommonGet("/ISAPI/System/capabilities")
+}

+ 41 - 0
isapi_system_deviceInfo.go

@@ -0,0 +1,41 @@
+package isapi
+
+import (
+	"encoding/xml"
+)
+
+// DeviceInfo 设备信息
+type DeviceInfo struct {
+	DeviceName           string `xml:"deviceName,omitempty" json:"deviceName,omitempty"`
+	DeviceID             string `xml:"deviceID,omitempty" json:"deviceID,omitempty"`
+	DeviceDescription    string `xml:"deviceDescription,omitempty" json:"deviceDescription,omitempty"`
+	DeviceLocation       string `xml:"deviceLocation,omitempty" json:"deviceLocation,omitempty"`
+	SystemContact        string `xml:"systemContact,omitempty" json:"systemContact,omitempty"` //生产商
+	Model                string `xml:"model,omitempty" json:"model,omitempty"`
+	SerialNumber         string `xml:"serialNumber,omitempty" json:"serialNumber,omitempty"`
+	MacAddress           string `xml:"macAddress,omitempty" json:"macAddress,omitempty"`
+	FirmwareVersion      string `xml:"firmwareVersion,omitempty" json:"firmwareVersion,omitempty"`
+	FirmwareReleasedDate string `xml:"firmwareReleasedDate,omitempty" json:"firmwareReleasedDate,omitempty"`
+	EncoderVersion       string `xml:"encoderVersion,omitempty" json:"encoderVersion,omitempty"`
+	EncoderReleasedDate  string `xml:"encoderReleasedDate,omitempty" json:"encoderReleasedDate,omitempty"`
+	BootVersion          string `xml:"bootVersion,omitempty" json:"bootVersion,omitempty"`
+	BootReleasedDate     string `xml:"bootReleasedDate,omitempty" json:"bootReleasedDate,omitempty"`
+	HardwareVersion      string `xml:"hardwareVersion,omitempty" json:"hardwareVersion,omitempty"`
+	DeviceType           string `xml:"deviceType,omitempty" json:"deviceType,omitempty"`
+	TelecontrolID        string `xml:"telecontrolID,omitempty" json:"telecontrolID,omitempty"`
+	SupportBeep          string `xml:"supportBeep,omitempty" json:"supportBeep,omitempty"`
+	SupportVideoLoss     string `xml:"supportVideoLoss" json:"supportVideoLoss"`
+	FirmwareVersionInfo  string `xml:"firmwareVersionInfo" json:"firmwareVersionInfo"`
+	Manufacturer         string `xml:"manufacturer" json:"manufacturer"`
+	SubSerialNumber      string `xml:"subSerialNumber" json:"subSerialNumber"`
+	OEMCode              string `xml:"OEMCode" json:"OEMCode"`
+}
+
+func (c *Client) GetDeviceInfo() (resp DeviceInfo, err error) {
+	bytes, err := c.CommonGet("/ISAPI/System/deviceInfo")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}

+ 5 - 0
isapi_system_email.go

@@ -0,0 +1,5 @@
+package isapi
+
+func (c *Client) PutEmail(data []byte) ([]byte, error) {
+	return c.CommonPut(data, "/ISAPI/System/Network/mailing/1")
+}

+ 42 - 0
isapi_system_motionDetection.go

@@ -0,0 +1,42 @@
+package isapi
+
+type MotionDetection struct {
+	Enabled          string `xml:"enabled"`
+	EnableHighlight  string `xml:"enableHighlight"`
+	SamplingInterval string `xml:"samplingInterval"`
+	StartTriggerTime string `xml:"startTriggerTime"`
+	EndTriggerTime   string `xml:"endTriggerTime"`
+	RegionType       string `xml:"regionType"`
+	Grid             struct {
+		RowGranularity    string `xml:"rowGranularity"`
+		ColumnGranularity string `xml:"columnGranularity"`
+	} `xml:"Grid"`
+	MotionDetectionLayout struct {
+		SensitivityLevel string `xml:"sensitivityLevel"`
+		Layout           struct {
+			GridMap    string `xml:"gridMap"`
+			RegionList struct {
+				Text   string `xml:",chardata"`
+				Size   string `xml:"size,attr"`
+				Region struct {
+					ID                    string `xml:"id"`
+					RegionCoordinatesList struct {
+						RegionCoordinates []struct {
+							PositionX string `xml:"positionX"`
+							PositionY string `xml:"positionY"`
+						} `xml:"RegionCoordinates"`
+					} `xml:"RegionCoordinatesList"`
+				} `xml:"Region"`
+			} `xml:"RegionList"`
+		} `xml:"layout"`
+		TargetType string `xml:"targetType"`
+	} `xml:"MotionDetectionLayout"`
+}
+
+func (c *Client) GetMotionDetection() ([]byte, error) {
+	return c.CommonGet("/ISAPI/System/Video/inputs/channels/1/motionDetection")
+}
+
+func (c *Client) PutMotionDetection(data []byte) ([]byte, error) {
+	return c.CommonPut(data, "/ISAPI/System/Video/inputs/channels/1/motionDetection")
+}

+ 47 - 0
isapi_system_time.go

@@ -0,0 +1,47 @@
+package isapi
+
+import (
+	"encoding/xml"
+	"net/url"
+)
+
+// Time
+type Time struct {
+	XMLName      xml.Name `xml:"Time,omitempty"`
+	XMLVersion   string   `xml:"version,attr"`
+	XMLNamespace string   `xml:"xmlns,attr"`
+	TimeMode     string   `xml:"timeMode,omitempty" json:"timeMode,omitempty"` //校时方式,[NTP#NTP校时,manual#手动校时,satellite#卫星校时,platform#平台校时,NONE#不允校时或无校时源,GB28181#GB28181校时,PTP#PTP校时]
+	LocalTime    string   `xml:"localTime,omitempty" json:"localTime,omitempty"`
+	TimeZone     string   `xml:"timeZone,omitempty" json:"timeZone,omitempty"` //CST为时区名称,-8:00:00为(UTC时间-本地时间)
+}
+
+// GetTime 获取时间信息
+func (c *Client) GetTime() (resp *Time, err error) {
+	path := "/ISAPI/System/time"
+	u, err := url.Parse(c.BaseURL + path)
+	if err != nil {
+		return nil, err
+	}
+	body, err := c.Get(u)
+	if err != nil {
+		return nil, err
+	}
+	err = xml.Unmarshal(body, &resp)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+// PutTime 更新时间
+func (c *Client) PutTime(data []byte) (resp []byte, err error) {
+	u, err := url.Parse(c.BaseURL + "/ISAPI/System/time")
+	if err != nil {
+		return nil, err
+	}
+	resp, err = c.PutXML(u, data)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}

+ 45 - 0
opreation.go

@@ -0,0 +1,45 @@
+package isapi
+
+// Operation 操作相关主题
+type Operation string
+
+const (
+	GetDeviceInfo Operation = "GetDeviceInfo" //获取摄像头信息
+	GetSystemCap  Operation = "GetSystemCap"  //获取系统能力
+	GetChanCap    Operation = "GetChanCap"    //获取指定通道摄像头能力
+	PutEmail      Operation = "PutEmail"
+
+	SetHosts   Operation = "SetHosts" //配置事件监听服务器
+	SetSIP     Operation = "SetSIP"   //配置sip服务器
+	SetSIPInfo Operation = "SetSIPInfo"
+
+	GetTamperDetection Operation = "GetTamperDetection" //获取指定通道视频遮盖检测规则
+	PutTamperDetection Operation = "PutTamperDetection" //配置指定通道视频遮盖检测规则
+
+	GetMotionDetection Operation = "GetMotionDetection" //获取移动侦测参数
+	PutMotionDetection Operation = "PutMotionDetection" //配置移动侦测参数
+
+	GetLineDetectionCap Operation = "GetLineDetectionCap" //获取单个通道越界规则参数配置能力
+	GetLineDetectionCal Operation = "GetLineDetectionCal" //获取监测目标最大和最小尺寸
+	PutLineDetectionCal Operation = "PutLineDetectionCal" //配置监测目标最大和最小尺寸
+	GetLineDetection    Operation = "GetLineDetection"    //获取越界侦测参数
+	PutLineDetection    Operation = "PutLineDetection"    //配置越界侦测参数
+
+	GetFieldDetectionCap Operation = "GetFieldDetectionCap" //获取单个通道区域入侵规则参数配置能力
+	GetFieldDetectionCal Operation = "GetFieldDetectionCal" //获取监测目标最大和最小尺寸
+	PutFieldDetectionCal Operation = "PutFieldDetectionCal" //配置监测目标最大和最小尺寸
+	GetFieldDetection    Operation = "GetFieldDetection"    //获取区域入侵侦测参数
+	PutFieldDetection    Operation = "PutFieldDetection"    //配置区域入侵侦测参数
+
+	GetRegionEntranceCap Operation = "GetRegionEntranceCap" //获取单个通道进入区域规则参数配置能力
+	GetRegionEntranceCal Operation = "GetRegionEntranceCal" //获取监测目标最大和最小尺寸
+	PutRegionEntranceCal Operation = "PutRegionEntranceCal" //配置监测目标最大和最小尺寸
+	GetRegionEntrance    Operation = "GetRegionEntrance"    //获取进入区域侦测参数
+	PutRegionEntrance    Operation = "PutRegionEntrance"    //配置进入区域侦测参数
+
+	GetRegionExitingCap Operation = "GetRegionExitingCap" //获取单个通道离开区域规则参数配置能力
+	GetRegionExitingCal Operation = "GetRegionExitingCal" //获取监测目标最大和最小尺寸
+	PutRegionExitingCal Operation = "PutRegionExitingCal" //配置监测目标最大和最小尺寸
+	GetRegionExiting    Operation = "GetRegionExiting"    //获取离开区域侦测参数
+	PutRegionExiting    Operation = "PutRegionExiting"    //配置离开区域侦测参数
+)

+ 9 - 0
response.go

@@ -0,0 +1,9 @@
+package isapi
+
+type ResponseStatus struct {
+	RequestURL    string `xml:"requestURL" json:"requestURL"`
+	StatusCode    int    `xml:"statusCode" json:"statusCode"`
+	StatusString  string `xml:"statusString" json:"statusString"`
+	SubStatusCode string `xml:"subStatusCode" json:"subStatusCode"`
+	Description   string `xml:"description" json:"description"`
+}

+ 190 - 0
server.go

@@ -0,0 +1,190 @@
+package isapi
+
+import (
+	"encoding/xml"
+	"fmt"
+	mail "github.com/xhit/go-simple-mail/v2"
+	"io"
+	"io/ioutil"
+	"log"
+	"mime/multipart"
+	"net/http"
+	"strings"
+	"time"
+)
+
+type Server struct {
+}
+
+func (s *Server) Start() {
+	http.HandleFunc("/event", handler)
+	log.Fatal("事件监听服务启动失败", http.ListenAndServe(":8850", nil))
+}
+
+func (s *Server) Stop() {
+
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+	go func() {
+		//监听主机应答固定,直接先应答
+		w.WriteHeader(200)
+		w.Header().Add("Date", time.Now().String())
+		w.Header().Add("Connection", "close")
+	}()
+	//logRequest(r)
+	contentType := r.Header.Get("Content-Type")
+	if strings.Contains(contentType, "application/xml") {
+		bytes, err := ioutil.ReadAll(r.Body)
+		if err != nil {
+			return
+		}
+		var event EventNotificationAlert
+		err = xml.Unmarshal(bytes, &event)
+		if err != nil {
+			return
+		}
+		//处理事件 todo 邮箱
+		handleEvent_(event)
+	} else if strings.Contains(contentType, "multipart/form-data") {
+		//fmt.Println("multipart/form-data 事件")
+		handleMultipart(r)
+	} else {
+		return
+	}
+}
+
+//TODO 限制事件重复触发,一段时间内不重复发送邮件,但保持报警状态
+
+// 处理多文件事件
+func handleMultipart(r *http.Request) {
+	// todo  远程联动-ip音柱
+	multipartReader := multipart.NewReader(r.Body, "boundary")
+	var msg string //邮件消息
+	// 循环读取每个 part
+	var eventAlert EventNotificationAlert
+	for {
+		part, err := multipartReader.NextPart()
+		//defer part.Close()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Println("Failed to read part:", err)
+			continue
+		}
+		// 检查 part 的 Content-Disposition
+		formName := part.FormName()
+		fmt.Println("formName", formName)
+		if formName != "intrusionImage" {
+			//不含图片的xml部分数据
+			xmlData, err := ioutil.ReadAll(part)
+			if err != nil {
+				return
+			}
+			xml.Unmarshal(xmlData, &eventAlert)
+			//event.Ip = eventAlert.IpAddress
+			//event.Type = eventAlert.EventType
+			//event.StartTime = eventAlert.DateTime
+			msg = handleEvent_(eventAlert)
+			continue
+		}
+		fmt.Printf("eventAlert:%+v\n", eventAlert)
+		//处理图片部分数据
+		contentType := part.Header.Get("Content-Type")
+		//eventCode := part.Header.Get("Content-ID")
+		picName := timeFmt(eventAlert.DateTime) + ".jpeg"
+		//event.Name = picName
+		data, _ := ioutil.ReadAll(part)
+		f := &mail.File{
+			Name:     picName,
+			MimeType: contentType,
+			Data:     data,
+			Inline:   true,
+		}
+		//邮件通知
+		SendAlarmEmail(eventAlert.MacAddress, msg, f)
+	}
+}
+
+func handleEvent_(event EventNotificationAlert) string {
+	var eType string
+	if event.EventType == "duration" {
+		eType = event.DurationList.Duration[0].RelationEvent
+	} else {
+		eType = event.EventType
+	}
+	return fmt.Sprintf("事件类型:%s,时间:%s", sMap[eType], timeFmt(event.DateTime))
+}
+
+func timeFmt(str string) string {
+	s := strings.Split(str, "T")
+	t := s[0]
+	s1 := strings.Split(s[1], ".")
+	s2 := strings.Split(s1[0], "+")
+	return t + " " + s2[0]
+}
+
+func logRequest(req *http.Request) {
+	// 打印请求行
+	fmt.Printf("%s %s %s\n", req.Method, req.URL.Path, req.Proto)
+
+	// 打印请求头
+	for name, headers := range req.Header {
+		for _, h := range headers {
+			fmt.Printf("%v: %v\n", name, h)
+		}
+	}
+
+	// 打印请求体
+	body, _ := ioutil.ReadAll(req.Body)
+	fmt.Printf("%s\n", body)
+}
+
+type EventNotificationAlert struct {
+	IpAddress           string `xml:"ipAddress"`
+	PortNo              string `xml:"portNo"`
+	Protocol            string `xml:"protocol"`
+	MacAddress          string `xml:"macAddress"`
+	ChannelID           string `xml:"channelID"`
+	DateTime            string `xml:"dateTime"`
+	ActivePostCount     string `xml:"activePostCount"`
+	EventType           string `xml:"eventType"`
+	EventState          string `xml:"eventState"`
+	EventDescription    string `xml:"eventDescription"`
+	DetectionRegionList struct {
+		DetectionRegionEntry []struct {
+			RegionID              string `xml:"regionID"`
+			SensitivityLevel      string `xml:"sensitivityLevel"`
+			RegionCoordinatesList struct {
+				RegionCoordinates []struct {
+					PositionX string `xml:"positionX"`
+					PositionY string `xml:"positionY"`
+				} `xml:"RegionCoordinates"`
+			} `xml:"RegionCoordinatesList"`
+			DetectionTarget string `xml:"detectionTarget"`
+			TargetRect      struct {
+				X      string `xml:"X"`
+				Y      string `xml:"Y"`
+				Width  string `xml:"width"`
+				Height string `xml:"height"`
+			} `xml:"TargetRect"`
+		} `xml:"DetectionRegionEntry"`
+	} `xml:"DetectionRegionList"`
+	ChannelName               string `xml:"channelName"`
+	DetectionPictureTransType string `xml:"detectionPictureTransType"`
+	DetectionPicturesNumber   string `xml:"detectionPicturesNumber"`
+	IsDataRetransmission      string `xml:"isDataRetransmission"`
+	DurationList              struct {
+		Duration []struct {
+			RelationEvent string `xml:"relationEvent"`
+		} `xml:"Duration"`
+	} `xml:"DurationList"`
+}
+
+var sMap = map[string]string{
+	"shelteralarm":   "遮盖报警",
+	"regionEntrance": "进入区域",
+	"fielddetection": "区域入侵",
+	"linedetection":  "越界侦测",
+}

+ 84 - 0
server_.go

@@ -0,0 +1,84 @@
+package isapi
+
+import (
+	"fmt"
+	mail "github.com/xhit/go-simple-mail/v2"
+	"log"
+)
+
+func SendAlarmEmail(cameraMac string, msg string, file *mail.File) {
+	var html = `
+<!DOCTYPE html>
+<html>
+<head><title>报警通知</title></head>
+<body>
+<h5>%s</h5>
+<h5><a href="http://192.168.110.69:8889/user/userUnbindEmail?id=%d&email=%s">不再接收龙弛防溺水报警邮箱通知!</a></h5>
+</body>
+</html>
+`
+	//查出所有相关email
+	//var emails []UserEmails
+	//
+	//for _, v := range emails {
+	//	body := fmt.Sprintf(html, msg, v.Uid, v.Email)
+	//	EmailPicture(v.Email,
+	//		"防溺水通知",
+	//		body,
+	//		file)
+	//}
+	body := fmt.Sprintf(html, msg, 1, "1104038181@qq.com")
+	EmailPicture("1104038181@qq.com",
+		"防溺水通知",
+		body,
+		file)
+}
+
+type UserEmails struct {
+	Uid   uint   `json:"uid"`
+	Email string `json:"email"`
+}
+
+var emailClient = func() *mail.SMTPServer {
+	// 创建邮件客户端
+	client := mail.NewSMTPClient()
+	// 设置SMTP服务器和认证信息
+	client.Host = "smtp.163.com"            // 替换为你的SMTP服务器地址
+	client.Port = 25                        // 替换为SMTP服务器端口
+	client.Username = "17673481176@163.com" // 替换为SMTP服务器的用户名
+	client.Password = "kk992471"            // 替换为SMTP服务器的密码
+	return client
+}()
+
+func EmailPicture(To, subject, data string, pic *mail.File) {
+	// 创建邮件客户端
+	smtpClient, err := emailClient.Connect()
+	if err != nil {
+		return
+	}
+	// 创建邮件对象
+	email := mail.NewMSG()
+	// 设置发件人
+	email.SetFrom("17673481176@163.com")
+
+	// 设置收件人
+	email.AddTo(To)
+
+	// 设置主题
+	email.SetSubject(subject)
+	// 设置html文本内容
+	email.SetBody(mail.TextHTML, data)
+
+	// 添加图片附件
+	if pic != nil {
+		email.Attach(pic)
+	}
+
+	// 发送邮件
+	err = email.Send(smtpClient)
+	if err != nil {
+		log.Println("116 Failed to send email:", err)
+		return
+	}
+	log.Println("Email sent successfully")
+}

+ 83 - 0
sip.go

@@ -0,0 +1,83 @@
+package isapi
+
+import (
+	"encoding/xml"
+)
+
+type SIPServerList struct {
+	SIPServer []struct {
+		ID        string `xml:"id" yaml:"ID"`
+		LocalPort string `xml:"localPort" yaml:"localPort"`
+		StreamID  string `xml:"streamID" yaml:"streamID"`
+		Standard  struct {
+			RegisterStatus string `xml:"registerStatus" yaml:"registerStatus"`
+			Enabled        string `xml:"enabled" yaml:"enabled"`
+			Registrar      string `xml:"registrar" yaml:"registrar"`
+			RegistrarPort  string `xml:"registrarPort" yaml:"registrarPort"`
+			Proxy          string `xml:"proxy" yaml:"proxy"`
+			ProxyPort      string `xml:"proxyPort" yaml:"proxyPort"`
+			DisplayName    string `xml:"displayName" yaml:"displayName"`
+			UserName       string `xml:"userName" yaml:"userName"`
+			AuthID         string `xml:"authID" yaml:"authID"`
+			Password       string `xml:"password" yaml:"password"`
+			Expires        string `xml:"expires" yaml:"expires"`
+		} `xml:"Standard" yaml:"Standard"`
+		GB28181 struct {
+			RegisterStatus        string `xml:"registerStatus" yaml:"registerStatus"`
+			Enabled               string `xml:"enabled" yaml:"enabled"`
+			Registrar             string `xml:"registrar" yaml:"registrar"`
+			RegistrarPort         string `xml:"registrarPort" yaml:"registrarPort"`
+			ServerId              string `xml:"serverId" yaml:"serverId"`
+			ServerDomain          string `xml:"serverDomain" yaml:"serverDomain"`
+			UserName              string `xml:"userName" yaml:"userName"`
+			AuthID                string `xml:"authID" yaml:"authID"`
+			Expires               string `xml:"expires" yaml:"expires"`
+			Password              string `xml:"password" yaml:"password"`
+			LiveTime              string `xml:"liveTime" yaml:"liveTime"`
+			HeartbeatTime         string `xml:"heartbeatTime" yaml:"heartbeatTime"`
+			HeartbeatCount        string `xml:"heartbeatCount" yaml:"heartbeatCount"`
+			TransportType         string `xml:"transportType" yaml:"transportType"`
+			RegisterInterval      string `xml:"registerInterval" yaml:"registerInterval"`
+			ProtocolVersion       string `xml:"protocolVersion" yaml:"protocolVersion"`
+			PlatformNo            string `xml:"platformNo" yaml:"platformNo"`
+			LocalPort             string `xml:"localPort" yaml:"localPort"`
+			UnidirectionEnabled   string `xml:"unidirectionEnabled" yaml:"unidirectionEnabled"`
+			VoiceBroadcastEnabled string `xml:"voiceBroadcastEnabled" yaml:"voiceBroadcastEnabled"`
+		} `xml:"GB28181" yaml:"GB28181"`
+	} `xml:"SIPServer"`
+}
+
+func (c *Client) PutSip(data []byte) (resp ResponseStatus, err error) {
+	bytes, err := c.CommonPut(data, "/ISAPI/System/Network/SIP")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+func (c *Client) PutSipInfo(data []byte) (resp ResponseStatus, err error) {
+	bytes, err := c.CommonPut(data, "/ISAPI/System/Network/SIP/1/SIPInfo")
+	if err != nil {
+		return
+	}
+	err = xml.Unmarshal(bytes, &resp)
+	return
+}
+
+type SIPInfo struct {
+	VideoID        string   `xml:"videoID"`
+	AlarmInList    []string `xml:"AlarmInList"`
+	VideoInputList []struct {
+		VideoInput struct {
+			ID           string `xml:"id"`
+			VideoInputID string `xml:"videoInputID"`
+		} `xml:"VideoInput"`
+	} `xml:"VideoInputList"`
+	AudioOutputList []struct {
+		AudioOutput struct {
+			ID            string `xml:"id"`
+			AudioOutputID string `xml:"audioOutputID"`
+		} `xml:"AudioOutput"`
+	} `xml:"AudioOutputList"`
+}