4 Commits

Author SHA1 Message Date
9d2db3672c Add SPI data handling and serialization support
Introduced `SpiParameters` and related structs to process SPI data. Added JSON marshaling/unmarshaling logic and a handler for the "SPI" command in the server. This enables parsing and transforming SPI data effectively for device communication.
2025-02-23 15:13:27 +03:00
519ad39c0f Removed DSM 2025-02-23 12:57:09 +03:00
7c348629d6 Add custom notFoundError type and improve error handling
Introduce the notFoundError struct to provide more detailed error messages for missing handlers like alarms, JSON operations, and payload types. Update error handling to leverage the new custom type and use errors.As for better flexibility. Additionally, update module imports to version v2 in relevant files.
2025-02-23 11:51:16 +03:00
58b1c67b97 Update module path to include version suffix
The module path was updated to align with Go versioning conventions by appending "/v2". This change ensures compatibility with Go's module versioning system and properly reflects the major version update.
2025-02-22 22:16:52 +03:00
6 changed files with 224 additions and 10 deletions

View File

@ -3,7 +3,7 @@ package main
import (
"errors"
"fmt"
"gitea.unprism.ru/KRBL/n9m"
"gitea.unprism.ru/KRBL/n9m/v2"
"io"
"net"
"os"
@ -88,6 +88,13 @@ func handleGetConfig(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
os.WriteFile(fmt.Sprintf("./%s.json", serial), pack.RawPayload, 0644)
var request n9m.ConfigModelSetRequest
if err = pack.GetParametersAs(&request); err != nil {
fmt.Println(err)
return err
}
return
}
@ -105,6 +112,18 @@ func handleCameraCoveredAlarm(sPack *n9m.SmartPackage, pack n9m.Package, respons
return nil
}
func handleSPI(_ *n9m.SmartPackage, pack n9m.Package) (err error) {
var params n9m.SpiParameters
if err = pack.GetParametersAs(&params); err != nil {
return
}
fmt.Printf("%+v\n", params)
return
}
func createSmartPackage(conn net.Conn) (pack *n9m.SmartPackage) {
pack = n9m.NewSmartPackage(conn)
@ -113,6 +132,7 @@ func createSmartPackage(conn net.Conn) (pack *n9m.SmartPackage) {
pack.AddJSONHandler("CERTIFICATE", "CONNECT", handleCertificateConnect)
pack.AddJSONHandler("CERTIFICATE", "KEEPALIVE", handleKeepAlive)
pack.AddJSONHandler("CONFIGMODEL", "GET", handleGetConfig)
pack.AddJSONHandler("DEVEMM", "SPI", handleSPI)
pack.AddAlarmHandler(n9m.AlarmTypeMotionDetection, handleUselessAlarms)

176
devemm.go
View File

@ -1,5 +1,12 @@
package n9m
import (
"encoding/json"
"fmt"
"strconv"
"time"
)
/*
// main server util
@ -36,3 +43,172 @@ func (e *Package) ResponseGeolocation(errorCode int, errorCause string, serial i
}
*/
// 3.4.5.28
type SpiParameters struct {
DriveFlag uint `json:"T"`
DataMask uint `json:"M"`
Position GPSData `json:"P"`
DeviceStatus SpiDeviceStatus `json:"S"`
}
// 3.4.5.28.1
type SpiDeviceStatus struct {
Status3G uint `json:"G3"`
Status3GStrength uint `json:"G3S"`
Status4G uint `json:"G4"`
Status4GStrength uint `json:"G4S"`
WIFIStatus uint `json:"W"`
WIFIStrength uint `json:"WS"`
Voltage float64 `json:"V"`
DeviceTemperature float64 `json:"DT"`
IndoorTemperature float64 `json:"TC"`
Speed float64 `json:"S"`
KeyIgnitionState uint `json:"SW"`
RecordStatus []uint `json:"RE"`
Time time.Time `json:"T"`
StorageDeviceNumber uint `json:"STC"`
StorageDeviceInfo []StorageDeviceInfo `json:"SINFO"`
VideoLossStatus []uint `json:"VS"`
Humidity float64 `json:"H"`
TotalMileage float64 `json:"TM"`
HardDriveHeating uint `json:"HTR"`
}
func (g *SpiDeviceStatus) MarshalJSON() ([]byte, error) {
var alias struct {
Status3G uint `json:"G3"`
Status3GStrength uint `json:"G3S"`
Status4G uint `json:"G4"`
Status4GStrength uint `json:"G4S"`
WIFIStatus uint `json:"W"`
WIFIStrength uint `json:"WS"`
Voltage uint `json:"V"`
DeviceTemperature uint `json:"DT"`
IndoorTemperature uint `json:"TC"`
Speed uint `json:"S"`
SpeedUnits uint `json:"SU"`
KeyIgnitionState uint `json:"SW"`
RecordStatus []uint `json:"RE"`
Time string `json:"T"`
StorageDeviceNumber uint `json:"STC"`
StorageDeviceInfo []StorageDeviceInfo `json:"SINFO"`
VideoLossStatus []uint `json:"VS"`
Humidity uint `json:"H"`
TotalMileage string `json:"TM"`
HardDriveHeating uint `json:"HTR"`
}
convert := func(v float64) uint {
if v < 0 {
return uint(-v * 100)
} else {
return uint((v + 100) * 100)
}
}
alias.Status3G = g.Status3G
alias.Status3GStrength = g.Status3GStrength
alias.Status4G = g.Status4G
alias.Status4GStrength = g.Status4GStrength
alias.WIFIStatus = g.WIFIStatus
alias.WIFIStrength = g.WIFIStrength
alias.Voltage = uint(g.Voltage * 100)
alias.DeviceTemperature = convert(g.DeviceTemperature)
alias.IndoorTemperature = convert(g.IndoorTemperature)
alias.Speed = uint(g.Speed * 100)
alias.SpeedUnits = 0
alias.KeyIgnitionState = g.KeyIgnitionState
alias.RecordStatus = g.RecordStatus
alias.Time = g.Time.Format("20060102150405")
alias.StorageDeviceNumber = g.StorageDeviceNumber
alias.StorageDeviceInfo = g.StorageDeviceInfo
alias.VideoLossStatus = g.VideoLossStatus
alias.Humidity = uint(g.Humidity * 10000)
alias.TotalMileage = fmt.Sprintf("%.6f", g.TotalMileage)
alias.HardDriveHeating = g.HardDriveHeating
return json.Marshal(alias)
}
func (g *SpiDeviceStatus) UnmarshalJSON(data []byte) (err error) {
var alias struct {
Status3G uint `json:"G3"`
Status3GStrength uint `json:"G3S"`
Status4G uint `json:"G4"`
Status4GStrength uint `json:"G4S"`
WIFIStatus uint `json:"W"`
WIFIStrength uint `json:"WS"`
Voltage uint `json:"V"`
DeviceTemperature uint `json:"TD"`
IndoorTemperature uint `json:"TC"`
Speed uint `json:"S"`
SpeedUnits uint `json:"SU"`
KeyIgnitionState uint `json:"SW"`
RecordStatus []uint `json:"RE"`
Time string `json:"T"`
StorageDeviceNumber uint `json:"STC"`
StorageDeviceInfo []StorageDeviceInfo `json:"SINFO"`
VideoLossStatus []uint `json:"VS"`
Humidity uint `json:"H"`
TotalMileage string `json:"TM"`
HardDriveHeating uint `json:"HTR"`
}
if err = json.Unmarshal(data, &alias); err != nil {
return
}
convert := func(v uint) float64 {
if v < 10000 {
return -float64(v) / 100
} else {
return float64(v-10000) / 100
}
}
g.Status3G = alias.Status3G
g.Status3GStrength = alias.Status3GStrength
g.Status4G = alias.Status4G
g.Status4GStrength = alias.Status4GStrength
g.WIFIStatus = alias.WIFIStatus
g.WIFIStrength = alias.WIFIStrength
g.Voltage = float64(alias.Voltage) / 100
g.DeviceTemperature = convert(alias.DeviceTemperature)
g.IndoorTemperature = convert(alias.IndoorTemperature)
g.Speed = float64(alias.Speed) / 100.0
switch alias.SpeedUnits {
case 0:
break
case 1:
g.Speed *= 1.609
default:
return fmt.Errorf("Strange speed units")
}
g.KeyIgnitionState = alias.KeyIgnitionState
g.RecordStatus = alias.RecordStatus
g.Time, _ = time.Parse("20060102150405", alias.Time)
g.StorageDeviceNumber = alias.StorageDeviceNumber
g.StorageDeviceInfo = alias.StorageDeviceInfo
g.VideoLossStatus = alias.VideoLossStatus
g.Humidity = float64(alias.Humidity) / 10000
if g.TotalMileage, err = strconv.ParseFloat(alias.TotalMileage, 64); err != nil {
return fmt.Errorf("invalid longitude: %w", err)
}
g.HardDriveHeating = alias.HardDriveHeating
return nil
}
// 3.4.5.28.3
type StorageDeviceInfo struct {
Type uint `json:"T"`
MediaTime uint `json:"O"`
Status uint `json:"S"`
Capacity uint `json:"TS"`
FreeCapacity uint `json:"LS"`
}

2
go.mod
View File

@ -1,4 +1,4 @@
module gitea.unprism.ru/KRBL/n9m
module gitea.unprism.ru/KRBL/n9m/v2
go 1.21.3

View File

@ -331,5 +331,5 @@ type Setting struct {
PSI PSI `json:"PSI,omitempty"`
SWUS SWUS `json:"SWUS,omitempty"`
DSM DSM `json:"DSM,omitempty"`
// DSM DSM `json:"DSM,omitempty"`
}

View File

@ -1,10 +1,19 @@
package n9m
import (
"errors"
"fmt"
"net"
)
type notFoundError struct {
message string
}
func (e *notFoundError) Error() string {
return fmt.Sprintf("not found %s", e.message)
}
func NewSmartPackage(conn net.Conn) *SmartPackage {
return &SmartPackage{
pack: Package{},
@ -42,7 +51,9 @@ func (pack *SmartPackage) handleAlarm() (err error) {
var processFunc AlarmProcessFunc
var ok bool
if processFunc, ok = pack.alarmProcess[params.AlarmType]; !ok {
return fmt.Errorf("unhanled alarm")
return &notFoundError{
message: fmt.Sprintf("alarm %d", params.AlarmType),
}
}
var response SendAlarmInfoResponse
@ -62,28 +73,35 @@ func (pack *SmartPackage) handleJson() (err error) {
return fmt.Errorf("invalid json payload type")
}
if err = pack.handleAlarm(); err == nil {
var nfErr *notFoundError
if err = pack.handleAlarm(); err == nil || errors.As(err, &nfErr) {
return
}
var processFunc ProcessFunc
var ok bool
if processFunc, ok = pack.jsonProcess[fmt.Sprintf("%s:%s", pack.pack.Payload.Module, pack.pack.Payload.Operation)]; !ok {
return fmt.Errorf("unhanled operation")
var key = fmt.Sprintf("%s:%s", pack.pack.Payload.Module, pack.pack.Payload.Operation)
if processFunc, ok = pack.jsonProcess[key]; !ok {
return &notFoundError{
message: fmt.Sprintf("json %s", key),
}
}
return processFunc(pack, pack.pack)
}
func (pack *SmartPackage) handle() (err error) {
if err = pack.handleJson(); err == nil {
var nfErr *notFoundError
if err = pack.handleJson(); err == nil || errors.As(err, &nfErr) {
return
}
var processFunc ProcessFunc
var ok bool
if processFunc, ok = pack.payloadProcess[pack.pack.PayloadType]; !ok {
return fmt.Errorf("unhanled payload type")
return &notFoundError{
message: fmt.Sprintf("payload type %d", pack.pack.PayloadType),
}
}
return processFunc(pack, pack.pack)

View File

@ -2,7 +2,7 @@ package test
import (
"fmt"
"gitea.unprism.ru/KRBL/n9m"
"gitea.unprism.ru/KRBL/n9m/v2"
"testing"
)