From 81bd0388494d45463de42cd91bd8c33f10f0030a Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期四, 17 六月 2021 10:27:21 +0800
Subject: [PATCH] 1. 新增用电量数据的接收协议 2. 调整socket接收模块的代码结构

---
 src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt             |   59 +
 src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt                   |  765 +++++++++++++++++++++
 src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt                    |   65 
 src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt |    8 
 src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt      |   39 
 src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt          |   24 
 src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt          |  159 ++++
 src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt             |    4 
 src/main/resources/generator/generatorConfig.xml                                 |    3 
 src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt      |   48 +
 src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt                 |   20 
 src/main/resources/mapper/ElectricMinuteValueMapper.xml                          |   30 
 src/main/kotlin/com/flightfeather/uav/UAVApplication.kt                          |   14 
 src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt      |   85 ++
 src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt               |   15 
 src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt            |    5 
 src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt           |    3 
 src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt             |   16 
 src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt       |   99 ++
 /dev/null                                                                        |  170 ----
 src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java     |  229 ++++++
 src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt           |    8 
 src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt          |  109 +++
 src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt                 |   87 ++
 src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt         |   30 
 src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt                    |   52 
 src/main/resources/application.yml                                               |    4 
 27 files changed, 1,854 insertions(+), 296 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/UAVApplication.kt b/src/main/kotlin/com/flightfeather/uav/UAVApplication.kt
index 307d5eb..0557bb3 100644
--- a/src/main/kotlin/com/flightfeather/uav/UAVApplication.kt
+++ b/src/main/kotlin/com/flightfeather/uav/UAVApplication.kt
@@ -1,6 +1,9 @@
 package com.flightfeather.uav
 
 import com.flightfeather.uav.socket.UnderwaySocketServer
+import com.flightfeather.uav.socket.processor.ElectricProcessor
+import com.flightfeather.uav.socket.processor.UnderwayProcessor
+import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.ApplicationRunner
 import org.springframework.boot.autoconfigure.SpringBootApplication
 import org.springframework.boot.runApplication
@@ -9,9 +12,18 @@
 @SpringBootApplication
 class UAVApplication{
 
+    @Autowired
+    lateinit var underwayProcessor: UnderwayProcessor
+
+    @Autowired
+    lateinit var electricProcessor: ElectricProcessor
+
+    private val socketServer = UnderwaySocketServer()
+
     @Bean
     fun runner() = ApplicationRunner{
-        UnderwaySocketServer().startServer(9030)
+        socketServer.startUnderwayServer(9030, underwayProcessor)
+        socketServer.startElectricServer(9009, electricProcessor)
     }
 }
 
diff --git a/src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt b/src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt
new file mode 100644
index 0000000..e8ff31b
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt
@@ -0,0 +1,20 @@
+package com.flightfeather.uav.common.utils
+
+/**
+ * @author riku
+ * Date: 2020/9/10
+ */
+object CommonUtil {
+
+    fun getSubStr(strData: String, startIndexStr: String, endIndexStr: String): String? {
+        try {
+            val startIndex = strData.indexOf(startIndexStr)
+            val endIndex = strData.indexOf(endIndexStr, startIndex + startIndexStr.length)
+            return strData.substring(startIndex, endIndex)
+        } catch (e: Exception) {
+//            println("瀛楁[$startIndexStr]鏃犳硶鑾峰彇")
+        }
+
+        return null
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt b/src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt
new file mode 100644
index 0000000..0b77150
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt
@@ -0,0 +1,765 @@
+package com.flightfeather.uav.common.utils
+
+import java.sql.Timestamp
+import java.text.ParsePosition
+import java.text.SimpleDateFormat
+import java.util.*
+
+class DateUtil {
+    private val threadLocal = ThreadLocal<SimpleDateFormat>()
+
+    private val `object` = Any()
+
+    /**
+     * 鑾峰彇SimpleDateFormat
+     * @param pattern 鏃ユ湡鏍煎紡
+     * @return SimpleDateFormat瀵硅薄
+     * @throws RuntimeException 寮傚父锛氶潪娉曟棩鏈熸牸寮�
+     */
+    @Throws(RuntimeException::class)
+    private fun getDateFormat(pattern: String): SimpleDateFormat {
+        var dateFormat: SimpleDateFormat? = threadLocal.get()
+        if (dateFormat == null) {
+            synchronized(`object`) {
+                if (dateFormat == null) {
+                    dateFormat = SimpleDateFormat(pattern)
+                    dateFormat!!.isLenient = false
+                    threadLocal.set(dateFormat)
+                }
+            }
+        }
+        dateFormat!!.applyPattern(pattern)
+        return dateFormat as SimpleDateFormat
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡涓殑鏌愭暟鍊笺�傚鑾峰彇鏈堜唤
+     * @param date 鏃ユ湡
+     * @param dateType 鏃ユ湡鏍煎紡
+     * @return 鏁板��
+     */
+    private fun getInteger(date: Date?, dateType: Int): Int {
+        var num = 0
+        val calendar = Calendar.getInstance()
+        if (date != null) {
+            calendar.time = date
+            num = calendar.get(dateType)
+        }
+        return num
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡涓煇绫诲瀷鐨勬煇鏁板�笺�傚澧炲姞鏃ユ湡
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param dateType 绫诲瀷
+     * @param amount 鏁板��
+     * @return 璁$畻鍚庢棩鏈熷瓧绗︿覆
+     */
+    private fun addInteger(date: String, dateType: Int, amount: Int): String? {
+        var dateString: String? = null
+        val dateStyle = getDateStyle(date)
+        if (dateStyle != null) {
+            var myDate = StringToDate(date, dateStyle)
+            myDate = addInteger(myDate, dateType, amount)
+            dateString = DateToString(myDate, dateStyle)
+        }
+        return dateString
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡涓煇绫诲瀷鐨勬煇鏁板�笺�傚澧炲姞鏃ユ湡
+     * @param date 鏃ユ湡
+     * @param dateType 绫诲瀷
+     * @param amount 鏁板��
+     * @return 璁$畻鍚庢棩鏈�
+     */
+    private fun addInteger(date: Date?, dateType: Int, amount: Int): Date? {
+        var myDate: Date? = null
+        if (date != null) {
+            val calendar = Calendar.getInstance()
+            calendar.time = date
+            calendar.add(dateType, amount)
+            myDate = calendar.time
+        }
+        return myDate
+    }
+
+    /**
+     * 鑾峰彇绮剧‘鐨勬棩鏈�
+     * @param timestamps 鏃堕棿long闆嗗悎
+     * @return 鏃ユ湡
+     */
+    private fun getAccurateDate(timestamps: List<Long>?): Date? {
+        var date: Date? = null
+        var timestamp: Long = 0
+        val map = HashMap<Long, LongArray>()
+        val absoluteValues = ArrayList<Long>()
+
+        if (timestamps != null && timestamps.size > 0) {
+            if (timestamps.size > 1) {
+                for (i in timestamps.indices) {
+                    for (j in i + 1 until timestamps.size) {
+                        val absoluteValue = Math.abs(timestamps[i] - timestamps[j])
+                        absoluteValues.add(absoluteValue)
+                        val timestampTmp = longArrayOf(timestamps[i], timestamps[j])
+                        map.put(absoluteValue, timestampTmp)
+                    }
+                }
+
+                // 鏈夊彲鑳芥湁鐩哥瓑鐨勬儏鍐点�傚2012-11鍜�2012-11-01銆傛椂闂存埑鏄浉绛夌殑銆傛鏃秏inAbsoluteValue涓�0
+                // 鍥犳涓嶈兘灏唌inAbsoluteValue鍙栭粯璁ゅ��0
+                var minAbsoluteValue: Long = -1
+                if (!absoluteValues.isEmpty()) {
+                    minAbsoluteValue = absoluteValues[0]
+                    for (i in 1 until absoluteValues.size) {
+                        if (minAbsoluteValue > absoluteValues[i]) {
+                            minAbsoluteValue = absoluteValues[i]
+                        }
+                    }
+                }
+
+                if (!minAbsoluteValue.equals(-1)) {
+                    val timestampsLastTmp = map[minAbsoluteValue]
+
+                    val dateOne = timestampsLastTmp?.get(0)
+                    val dateTwo = timestampsLastTmp?.get(1)
+                    if (absoluteValues.size > 1) {
+                        timestamp = if (Math.abs(dateOne!!) > Math.abs(dateTwo!!)) dateOne else dateTwo
+                    }
+                }
+            } else {
+                timestamp = timestamps[0]
+            }
+        }
+
+        if (timestamp != 0L) {
+            date = Date(timestamp)
+        }
+        return date
+    }
+
+    /**
+     * 鍒ゆ柇瀛楃涓叉槸鍚︿负鏃ユ湡瀛楃涓�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return true or false
+     */
+    fun isDate(date: String?): Boolean {
+        var isDate = false
+        if (date != null) {
+            if (getDateStyle(date) != null) {
+                isDate = true
+            }
+        }
+        return isDate
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡瀛楃涓茬殑鏃ユ湡椋庢牸銆傚け鏁楄繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏃ユ湡椋庢牸
+     */
+    fun getDateStyle(date: String?): DateStyle? {
+        var dateStyle: DateStyle? = null
+        val map = HashMap<Long, DateStyle>()
+        val timestamps = ArrayList<Long>()
+        for (style in DateStyle.values()) {
+            if (style.isShowOnly) {
+                continue
+            }
+            var dateTmp: Date? = null
+            if (date != null) {
+                try {
+                    val pos = ParsePosition(0)
+                    dateTmp = getDateFormat(style.value).parse(date, pos)
+                    if (pos.index != date.length) {
+                        dateTmp = null
+                    }
+                } catch (e: Exception) {
+                }
+
+            }
+            if (dateTmp != null) {
+                timestamps.add(dateTmp.time)
+                map.put(dateTmp.time, style)
+            }
+        }
+        val accurateDate = getAccurateDate(timestamps)
+        if (accurateDate != null) {
+            dateStyle = map[accurateDate.time]
+        }
+        return dateStyle
+    }
+
+
+    /**
+     * Timestamp -> String
+     *
+     */
+    fun timestampToString(ts: Timestamp, format: String): String {
+        var tsStr = ""
+        val sdf = SimpleDateFormat(format)
+        try {
+            //鏂规硶涓�
+            tsStr = sdf.format(ts)
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+
+        return tsStr
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓烘棩鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏃ユ湡
+     */
+    fun StringToDate(date: String): Date? {
+        val dateStyle = getDateStyle(date)
+        return StringToDate(date, dateStyle)
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓烘棩鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param pattern 鏃ユ湡鏍煎紡
+     * @return 鏃ユ湡
+     */
+    fun StringToDate(date: String?, pattern: String): Date? {
+        var myDate: Date? = null
+        if (date != null) {
+            try {
+                myDate = getDateFormat(pattern).parse(date)
+            } catch (e: Exception) {
+            }
+
+        }
+        return myDate
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓烘棩鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param dateStyle 鏃ユ湡椋庢牸
+     * @return 鏃ユ湡
+     */
+    fun StringToDate(date: String?, dateStyle: DateStyle?): Date? {
+        var myDate: Date? = null
+        if (dateStyle != null) {
+            myDate = StringToDate(date, dateStyle.value)
+        }
+        return myDate
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓烘棩鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param millisecondStamp 鏃ユ湡鏃堕棿鎴�
+     * @param dateStyle 鏃ユ湡椋庢牸
+     * @return 鏃ユ湡
+     */
+    fun LongToString(millisecondStamp: Long?, dateStyle: DateStyle?): String? {
+        var dateString: String? = null
+        if (dateStyle != null) {
+            dateString = DateToString(Date(millisecondStamp!!), dateStyle.value)
+        }
+        return dateString
+    }
+
+    /**
+     * 灏嗘棩鏈熻浆鍖栦负鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param pattern 鏃ユ湡鏍煎紡
+     * @return 鏃ユ湡瀛楃涓�
+     */
+    fun DateToString(date: Date?, pattern: String): String? {
+        var dateString: String? = null
+        if (date != null) {
+            try {
+                dateString = getDateFormat(pattern).format(date)
+            } catch (e: Exception) {
+            }
+        }
+        return dateString
+    }
+
+    /**
+     * 灏嗘棩鏈熻浆鍖栦负鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param dateStyle 鏃ユ湡椋庢牸
+     * @return 鏃ユ湡瀛楃涓�
+     */
+    fun DateToString(date: Date?, dateStyle: DateStyle?): String? {
+        var dateString: String? = null
+        if (dateStyle != null) {
+            dateString = DateToString(date, dateStyle.value)
+        }
+        return dateString
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param newPattern 鏂版棩鏈熸牸寮�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, newPattern: String): String? {
+        val oldDateStyle = getDateStyle(date)
+        return StringToString(date, oldDateStyle, newPattern)
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param newDateStyle 鏂版棩鏈熼鏍�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, newDateStyle: DateStyle): String? {
+        val oldDateStyle = getDateStyle(date)
+        return StringToString(date, oldDateStyle, newDateStyle)
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param olddPattern 鏃ф棩鏈熸牸寮�
+     * @param newPattern 鏂版棩鏈熸牸寮�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, olddPattern: String, newPattern: String): String? {
+        return DateToString(StringToDate(date, olddPattern), newPattern)
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param olddDteStyle 鏃ф棩鏈熼鏍�
+     * @param newParttern 鏂版棩鏈熸牸寮�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, olddDteStyle: DateStyle?, newParttern: String): String? {
+        var dateString: String? = null
+        if (olddDteStyle != null) {
+            dateString = StringToString(date, olddDteStyle.value, newParttern)
+        }
+        return dateString
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param olddPattern 鏃ф棩鏈熸牸寮�
+     * @param newDateStyle 鏂版棩鏈熼鏍�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, olddPattern: String, newDateStyle: DateStyle?): String? {
+        var dateString: String? = null
+        if (newDateStyle != null) {
+            dateString = StringToString(date, olddPattern, newDateStyle.value)
+        }
+        return dateString
+    }
+
+    /**
+     * 灏嗘棩鏈熷瓧绗︿覆杞寲涓哄彟涓�鏃ユ湡瀛楃涓层�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ф棩鏈熷瓧绗︿覆
+     * @param olddDteStyle 鏃ф棩鏈熼鏍�
+     * @param newDateStyle 鏂版棩鏈熼鏍�
+     * @return 鏂版棩鏈熷瓧绗︿覆
+     */
+    fun StringToString(date: String, olddDteStyle: DateStyle?, newDateStyle: DateStyle?): String? {
+        var dateString: String? = null
+        if (olddDteStyle != null && newDateStyle != null) {
+            dateString = StringToString(date, olddDteStyle.value, newDateStyle.value)
+        }
+        return dateString
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫勾浠姐�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param yearAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞骞翠唤鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addYear(date: String, yearAmount: Int): String? {
+        return addInteger(date, Calendar.YEAR, yearAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫勾浠姐�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param yearAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞骞翠唤鍚庣殑鏃ユ湡
+     */
+    fun addYear(date: Date, yearAmount: Int): Date? {
+        return addInteger(date, Calendar.YEAR, yearAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勬湀浠姐�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param monthAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞鏈堜唤鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addMonth(date: String, monthAmount: Int): String? {
+        return addInteger(date, Calendar.MONTH, monthAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勬湀浠姐�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param monthAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞鏈堜唤鍚庣殑鏃ユ湡
+     */
+    fun addMonth(date: Date, monthAmount: Int): Date? {
+        return addInteger(date, Calendar.MONTH, monthAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫ぉ鏁般�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param dayAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞澶╂暟鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addDay(date: String, dayAmount: Int): String? {
+        return addInteger(date, Calendar.DATE, dayAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫ぉ鏁般�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param dayAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞澶╂暟鍚庣殑鏃ユ湡
+     */
+    fun addDay(date: Date, dayAmount: Int): Date? {
+        return addInteger(date, Calendar.DATE, dayAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫皬鏃躲�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param hourAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞灏忔椂鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addHour(date: String, hourAmount: Int): String? {
+        return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫皬鏃躲�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param hourAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞灏忔椂鍚庣殑鏃ユ湡
+     */
+    fun addHour(date: Date, hourAmount: Int): Date? {
+        return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫垎閽熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param minuteAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞鍒嗛挓鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addMinute(date: String, minuteAmount: Int): String? {
+        return addInteger(date, Calendar.MINUTE, minuteAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勫垎閽熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param minuteAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞鍒嗛挓鍚庣殑鏃ユ湡
+     */
+    fun addMinute(date: Date, minuteAmount: Int): Date? {
+        return addInteger(date, Calendar.MINUTE, minuteAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勭閽熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param secondAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞绉掗挓鍚庣殑鏃ユ湡瀛楃涓�
+     */
+    fun addSecond(date: String, secondAmount: Int): String? {
+        return addInteger(date, Calendar.SECOND, secondAmount)
+    }
+
+    /**
+     * 澧炲姞鏃ユ湡鐨勭閽熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @param secondAmount 澧炲姞鏁伴噺銆傚彲涓鸿礋鏁�
+     * @return 澧炲姞绉掗挓鍚庣殑鏃ユ湡
+     */
+    fun addSecond(date: Date, secondAmount: Int): Date? {
+        return addInteger(date, Calendar.SECOND, secondAmount)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫勾浠姐�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 骞翠唤
+     */
+    fun getYear(date: String): Int {
+        return getYear(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫勾浠姐�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 骞翠唤
+     */
+    fun getYear(date: Date?): Int {
+        return getInteger(date, Calendar.YEAR)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬湀浠姐�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏈堜唤
+     */
+    fun getMonth(date: String): Int {
+        return getMonth(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬湀浠姐�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 鏈堜唤
+     */
+    fun getMonth(date: Date?): Int {
+        return getInteger(date, Calendar.MONTH) + 1
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫ぉ鏁般�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 澶�
+     */
+    fun getDay(date: String): Int {
+        return getDay(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫ぉ鏁般�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 澶�
+     */
+    fun getDay(date: Date?): Int {
+        return getInteger(date, Calendar.DATE)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫皬鏃躲�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 灏忔椂
+     */
+    fun getHour(date: String): Int {
+        return getHour(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫皬鏃躲�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 灏忔椂
+     */
+    fun getHour(date: Date?): Int {
+        return getInteger(date, Calendar.HOUR_OF_DAY)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫垎閽熴�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鍒嗛挓
+     */
+    fun getMinute(date: String): Int {
+        return getMinute(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勫垎閽熴�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 鍒嗛挓
+     */
+    fun getMinute(date: Date?): Int {
+        return getInteger(date, Calendar.MINUTE)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勭閽熴�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 绉掗挓
+     */
+    fun getSecond(date: String): Int {
+        return getSecond(StringToDate(date))
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勭閽熴�傚け璐ヨ繑鍥�0銆�
+     * @param date 鏃ユ湡
+     * @return 绉掗挓
+     */
+    fun getSecond(date: Date?): Int {
+        return getInteger(date, Calendar.SECOND)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡 銆傞粯璁yyy-MM-dd鏍煎紡銆傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏃ユ湡
+     */
+    fun getDate(date: String): String? {
+        return StringToString(date, DateStyle.YYYY_MM_DD)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡銆傞粯璁yyy-MM-dd鏍煎紡銆傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @return 鏃ユ湡
+     */
+    fun getDate(date: Date?): String? {
+        return DateToString(date, DateStyle.YYYY_MM_DD)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬椂闂淬�傞粯璁H:mm:ss鏍煎紡銆傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏃堕棿
+     */
+    fun getTime(date: String): String? {
+        return StringToString(date, DateStyle.HH_MM_SS)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬椂闂淬�傞粯璁H:mm:ss鏍煎紡銆傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @return 鏃堕棿
+     */
+    fun getTime(date: Date): String? {
+        return DateToString(date, DateStyle.HH_MM_SS)
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬槦鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @return 鏄熸湡
+     */
+    fun getWeek(date: String): Week? {
+        var week: Week? = null
+        val dateStyle = getDateStyle(date)
+        if (dateStyle != null) {
+            val myDate = StringToDate(date, dateStyle)
+            week = getWeek(myDate)
+        }
+        return week
+    }
+
+    /**
+     * 鑾峰彇鏃ユ湡鐨勬槦鏈熴�傚け璐ヨ繑鍥瀗ull銆�
+     * @param date 鏃ユ湡
+     * @return 鏄熸湡
+     */
+    fun getWeek(date: Date?): Week? {
+        var week: Week? = null
+        val calendar = Calendar.getInstance()
+        calendar.time = date!!
+        val weekNumber = calendar.get(Calendar.DAY_OF_WEEK) - 1
+        when (weekNumber) {
+            0 -> week = Week.SUNDAY
+            1 -> week = Week.MONDAY
+            2 -> week = Week.TUESDAY
+            3 -> week = Week.WEDNESDAY
+            4 -> week = Week.THURSDAY
+            5 -> week = Week.FRIDAY
+            6 -> week = Week.SATURDAY
+        }
+        return week
+    }
+
+    /**
+     * 鑾峰彇涓や釜鏃ユ湡鐩稿樊鐨勫ぉ鏁�
+     * @param date 鏃ユ湡瀛楃涓�
+     * @param otherDate 鍙︿竴涓棩鏈熷瓧绗︿覆
+     * @return 鐩稿樊澶╂暟銆傚鏋滃け璐ュ垯杩斿洖-1
+     */
+    fun getIntervalDays(date: String, otherDate: String): Int {
+        return getIntervalDays(StringToDate(date), StringToDate(otherDate))
+    }
+
+    /**
+     * @param date 鏃ユ湡
+     * @param otherDate 鍙︿竴涓棩鏈�
+     * @return 鐩稿樊澶╂暟銆傚鏋滃け璐ュ垯杩斿洖-1
+     */
+    fun getIntervalDays(date: Date?, otherDate: Date?): Int {
+        var num = -1
+        val dateTmp = StringToDate(getDate(date), DateStyle.YYYY_MM_DD)
+        val otherDateTmp = StringToDate(getDate(otherDate), DateStyle.YYYY_MM_DD)
+        if (dateTmp != null && otherDateTmp != null) {
+            val time = Math.abs(dateTmp.time - otherDateTmp.time)
+            num = (time / (24 * 60 * 60 * 1000)).toInt()
+        }
+        return num
+    }
+
+    enum class DateStyle private constructor(val value: String, val isShowOnly: Boolean) {
+
+        YYYYMMDD("yyyyMMdd", false),
+
+        YYYY_MM("yyyy-MM", false),
+        YYYY_MM_DD("yyyy-MM-dd", false),
+        YYYY_MM_DD_HH("yyyyMMddHH", false),
+        YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm", false),
+        YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss", false),
+
+        YYYY_MM_EN("yyyy/MM", false),
+        YYYY_MM_DD_EN("yyyy/MM/dd", false),
+        YYYY_MM_DD_HH_MM_EN("yyyy/MM/dd HH:mm", false),
+        YYYY_MM_DD_HH_MM_SS_EN("yyyy/MM/dd HH:mm:ss", false),
+
+        YYYY_MM_CN("yyyy骞碝M鏈�", false),
+        YYYY_MM_DD_CN("yyyy骞碝M鏈坉d鏃�", false),
+        YYYY_MM_DD_HH_MM_CN("yyyy骞碝M鏈坉d鏃� HH:mm", false),
+        YYYY_MM_DD_HH_MM_SS_CN("yyyy骞碝M鏈坉d鏃� HH:mm:ss", false),
+
+        HH_MM("HH:mm", true),
+        HH_MM_SS("HH:mm:ss", true),
+
+        MM_DD("MM-dd", true),
+        MM_DD_HH_MM("MM-dd HH:mm", true),
+        MM_DD_HH_MM_SS("MM-dd HH:mm:ss", true),
+
+        MM_DD_EN("MM/dd", true),
+        MM_DD_HH_MM_EN("MM/dd HH:mm", true),
+        MM_DD_HH_MM_SS_EN("MM/dd HH:mm:ss", true),
+
+        MM_DD_CN("MM鏈坉d鏃�", true),
+        MM_DD_HH_MM_CN("MM鏈坉d鏃� HH:mm", true),
+        MM_DD_HH_MM_SS_CN("MM鏈坉d鏃� HH:mm:ss", true)
+    }
+
+    enum class Week private constructor(name_cn: String, name_en: String, name_enShort: String, number: Int) {
+
+        MONDAY("鏄熸湡涓�", "Monday", "Mon.", 1),
+        TUESDAY("鏄熸湡浜�", "Tuesday", "Tues.", 2),
+        WEDNESDAY("鏄熸湡涓�", "Wednesday", "Wed.", 3),
+        THURSDAY("鏄熸湡鍥�", "Thursday", "Thur.", 4),
+        FRIDAY("鏄熸湡浜�", "Friday", "Fri.", 5),
+        SATURDAY("鏄熸湡鍏�", "Saturday", "Sat.", 6),
+        SUNDAY("鏄熸湡鏃�", "Sunday", "Sun.", 7);
+
+        var chineseName: String
+            internal set
+        var aname: String
+            internal set
+        var shortName: String
+            internal set
+        var number: Int = 0
+            internal set
+
+        init {
+            this.chineseName = name_cn
+            this.aname = name_en
+            this.shortName = name_enShort
+            this.number = number
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java b/src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java
new file mode 100644
index 0000000..b6c122d
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java
@@ -0,0 +1,229 @@
+package com.flightfeather.uav.domain.entity;
+
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "el_minutevalue")
+public class ElectricMinuteValue {
+    @Id
+    @Column(name = "MV_ID")
+    private Integer mvId;
+
+    @Column(name = "MV_Stat_Code")
+    private String mvStatCode;
+
+    @Column(name = "MV_Create_Time")
+    private Date mvCreateTime;
+
+    @Column(name = "MV_Data_Time")
+    private Date mvDataTime;
+
+    @Column(name = "MV_Electricity_A")
+    private Double mvElectricityA;
+
+    @Column(name = "MV_Electricity_B")
+    private Double mvElectricityB;
+
+    @Column(name = "MV_Electricity_C")
+    private Double mvElectricityC;
+
+    @Column(name = "MV_Voltage_A")
+    private Double mvVoltageA;
+
+    @Column(name = "MV_Voltage_B")
+    private Double mvVoltageB;
+
+    @Column(name = "MV_Voltage_C")
+    private Double mvVoltageC;
+
+    @Column(name = "MV_Power_A")
+    private Double mvPowerA;
+
+    @Column(name = "MV_Power_B")
+    private Double mvPowerB;
+
+    @Column(name = "MV_Power_C")
+    private Double mvPowerC;
+
+    /**
+     * @return MV_ID
+     */
+    public Integer getMvId() {
+        return mvId;
+    }
+
+    /**
+     * @param mvId
+     */
+    public void setMvId(Integer mvId) {
+        this.mvId = mvId;
+    }
+
+    /**
+     * @return MV_Stat_Code
+     */
+    public String getMvStatCode() {
+        return mvStatCode;
+    }
+
+    /**
+     * @param mvStatCode
+     */
+    public void setMvStatCode(String mvStatCode) {
+        this.mvStatCode = mvStatCode == null ? null : mvStatCode.trim();
+    }
+
+    /**
+     * @return MV_Create_Time
+     */
+    public Date getMvCreateTime() {
+        return mvCreateTime;
+    }
+
+    /**
+     * @param mvCreateTime
+     */
+    public void setMvCreateTime(Date mvCreateTime) {
+        this.mvCreateTime = mvCreateTime;
+    }
+
+    /**
+     * @return MV_Data_Time
+     */
+    public Date getMvDataTime() {
+        return mvDataTime;
+    }
+
+    /**
+     * @param mvDataTime
+     */
+    public void setMvDataTime(Date mvDataTime) {
+        this.mvDataTime = mvDataTime;
+    }
+
+    /**
+     * @return MV_Electricity_A
+     */
+    public Double getMvElectricityA() {
+        return mvElectricityA;
+    }
+
+    /**
+     * @param mvElectricityA
+     */
+    public void setMvElectricityA(Double mvElectricityA) {
+        this.mvElectricityA = mvElectricityA;
+    }
+
+    /**
+     * @return MV_Electricity_B
+     */
+    public Double getMvElectricityB() {
+        return mvElectricityB;
+    }
+
+    /**
+     * @param mvElectricityB
+     */
+    public void setMvElectricityB(Double mvElectricityB) {
+        this.mvElectricityB = mvElectricityB;
+    }
+
+    /**
+     * @return MV_Electricity_C
+     */
+    public Double getMvElectricityC() {
+        return mvElectricityC;
+    }
+
+    /**
+     * @param mvElectricityC
+     */
+    public void setMvElectricityC(Double mvElectricityC) {
+        this.mvElectricityC = mvElectricityC;
+    }
+
+    /**
+     * @return MV_Voltage_A
+     */
+    public Double getMvVoltageA() {
+        return mvVoltageA;
+    }
+
+    /**
+     * @param mvVoltageA
+     */
+    public void setMvVoltageA(Double mvVoltageA) {
+        this.mvVoltageA = mvVoltageA;
+    }
+
+    /**
+     * @return MV_Voltage_B
+     */
+    public Double getMvVoltageB() {
+        return mvVoltageB;
+    }
+
+    /**
+     * @param mvVoltageB
+     */
+    public void setMvVoltageB(Double mvVoltageB) {
+        this.mvVoltageB = mvVoltageB;
+    }
+
+    /**
+     * @return MV_Voltage_C
+     */
+    public Double getMvVoltageC() {
+        return mvVoltageC;
+    }
+
+    /**
+     * @param mvVoltageC
+     */
+    public void setMvVoltageC(Double mvVoltageC) {
+        this.mvVoltageC = mvVoltageC;
+    }
+
+    /**
+     * @return MV_Power_A
+     */
+    public Double getMvPowerA() {
+        return mvPowerA;
+    }
+
+    /**
+     * @param mvPowerA
+     */
+    public void setMvPowerA(Double mvPowerA) {
+        this.mvPowerA = mvPowerA;
+    }
+
+    /**
+     * @return MV_Power_B
+     */
+    public Double getMvPowerB() {
+        return mvPowerB;
+    }
+
+    /**
+     * @param mvPowerB
+     */
+    public void setMvPowerB(Double mvPowerB) {
+        this.mvPowerB = mvPowerB;
+    }
+
+    /**
+     * @return MV_Power_C
+     */
+    public Double getMvPowerC() {
+        return mvPowerC;
+    }
+
+    /**
+     * @param mvPowerC
+     */
+    public void setMvPowerC(Double mvPowerC) {
+        this.mvPowerC = mvPowerC;
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt b/src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt
new file mode 100644
index 0000000..c91ad62
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.uav.domain.mapper
+
+import com.flightfeather.uav.domain.MyMapper
+import com.flightfeather.uav.domain.entity.ElectricMinuteValue
+import org.apache.ibatis.annotations.Mapper
+
+@Mapper
+interface ElectricMinuteValueMapper : MyMapper<ElectricMinuteValue?>
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt b/src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt
new file mode 100644
index 0000000..8179ccb
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.uav.repository
+
+import com.flightfeather.uav.socket.bean.ElectricMessage
+
+interface ElectricRepository {
+
+    fun saveData(electricMessage: ElectricMessage): Int
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt b/src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt
new file mode 100644
index 0000000..d853089
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt
@@ -0,0 +1,30 @@
+package com.flightfeather.uav.repository.impl
+
+import com.flightfeather.uav.domain.entity.ElectricMinuteValue
+import com.flightfeather.uav.domain.mapper.ElectricMinuteValueMapper
+import com.flightfeather.uav.repository.ElectricRepository
+import com.flightfeather.uav.socket.bean.ElectricMessage
+import org.springframework.stereotype.Repository
+import java.util.*
+
+@Repository
+class ElectricDapImpl(val electricMinuteValueMapper: ElectricMinuteValueMapper) : ElectricRepository {
+    override fun saveData(electricMessage: ElectricMessage): Int {
+        val minuteValue = ElectricMinuteValue().apply {
+            mvStatCode = electricMessage.mn
+            mvCreateTime = Date()
+            mvDataTime = electricMessage.dataTime
+            mvElectricityA = electricMessage.electricityA
+            mvElectricityB = electricMessage.electricityB
+            mvElectricityC = electricMessage.electricityC
+            mvVoltageA = electricMessage.voltageA
+            mvVoltageB = electricMessage.voltageB
+            mvVoltageC = electricMessage.voltageC
+            mvPowerA = electricMessage.powerA
+            mvPowerB = electricMessage.powerB
+            mvPowerC = electricMessage.powerC
+        }
+
+        return electricMinuteValueMapper.insert(minuteValue)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt b/src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt
index d387fb3..c04b467 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt
@@ -11,38 +11,38 @@
  */
 class DeviceSession {
 
-    companion object{
-        private val deviceMap = ConcurrentHashMap<String, ChannelHandlerContext?>()
-        private val typeMap = ConcurrentHashMap<String, List<AirTypeData>>()
+    companion object {
         private const val DEFAULT_DEVICE = "default_device"
+    }
+    private val deviceMap = ConcurrentHashMap<String, ChannelHandlerContext?>()
+    private val typeMap = ConcurrentHashMap<String, List<AirTypeData>>()
 
-        fun saveDevice(deviceCode: String?, channel: ChannelHandlerContext?) {
-            deviceCode?.let {
-                deviceMap.put(deviceCode, channel)
-            }
+    fun saveDevice(deviceCode: String?, channel: ChannelHandlerContext?) {
+        deviceCode?.let {
+            deviceMap.put(deviceCode, channel)
         }
+    }
 
-        fun getDevice(deviceCode: String?): ChannelHandlerContext? {
-            return if (deviceMap.containsKey(deviceCode))
-                deviceMap[deviceCode]
-            else
-                null
+    fun getDevice(deviceCode: String?): ChannelHandlerContext? {
+        return if (deviceMap.containsKey(deviceCode))
+            deviceMap[deviceCode]
+        else
+            null
+    }
+
+    fun saveAirType(deviceCode: String?, types: List<AirTypeData>) {
+        if (deviceCode == null) {
+            typeMap[DEFAULT_DEVICE] = types
+        } else {
+            typeMap[deviceCode] = types
         }
+    }
 
-        fun saveAirType(deviceCode: String?, types: List<AirTypeData>) {
-            if (deviceCode == null) {
-                typeMap[DEFAULT_DEVICE] = types
-            } else {
-                typeMap[deviceCode] = types
-            }
-        }
-
-        fun getAirType(deviceCode: String?): List<AirTypeData>? {
-            return when {
-                deviceCode == null -> typeMap[DEFAULT_DEVICE]
-                typeMap.containsKey(deviceCode) -> typeMap[deviceCode]
-                else -> null
-            }
+    fun getAirType(deviceCode: String?): List<AirTypeData>? {
+        return when {
+            deviceCode == null -> typeMap[DEFAULT_DEVICE]
+            typeMap.containsKey(deviceCode) -> typeMap[deviceCode]
+            else -> null
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt b/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
index fc5202e..d08948c 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
@@ -1,5 +1,6 @@
 package com.flightfeather.uav.socket
 
+import com.flightfeather.uav.socket.processor.BaseProcessor
 import io.netty.channel.ChannelHandlerContext
 import io.netty.channel.ChannelInboundHandlerAdapter
 import io.netty.util.AttributeKey
@@ -8,57 +9,57 @@
 import java.util.*
 
 
-class ServerHandler : ChannelInboundHandlerAdapter() {
-
-    companion object {
-        private const val TAG = "UAV"
-    }
+class ServerHandler(private val processor: BaseProcessor) : ChannelInboundHandlerAdapter() {
 
     val attributeKey = AttributeKey.valueOf<String>("deviceCode")
-    val messageManager = MessageManager()
 
     override fun channelRegistered(ctx: ChannelHandlerContext?) {
         super.channelRegistered(ctx)
-        println()
-        println("------${TAG}绔彛鏈塈P杩炴帴锛歔ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
+        println("------銆�${processor.tag}銆慖P杩炴帴锛歔ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
 //        ctx?.fireChannelActive()
     }
 
     override fun channelActive(ctx: ChannelHandlerContext?) {
-        println()
-        println("------${TAG}绔彛鏈塈P婵�娲伙細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
+        println("------銆�${processor.tag}銆慖P婵�娲伙細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
         super.channelActive(ctx)
     }
 
     override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
         super.channelRead(ctx, msg)
+        println("------銆�${processor.tag}銆戞敹鍒扮殑鍘熷鏁版嵁锛歔ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
 
-        val sb = StringBuilder()
+        var str = ""
 
-        if (msg is ByteArray) {
-            println()
-            println("------${TAG}鏀跺埌鐨勫師濮嬫暟鎹細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
-            msg.forEach {
-                val a: Int = if (it < 0) {
-                    it + 256
-                } else {
-                    it.toInt()
+        when (msg) {
+            is ByteArray -> {
+                val sb = StringBuilder()
+
+                msg.forEach {
+                    var a = 0
+                    a = if (it < 0) {
+                        it + 256
+                    } else {
+                        it.toInt()
+                    }
+                    val s = if (a < 16) {
+                        "0${a.toString(16)}"
+                    } else {
+                        a.toString(16)
+                    }
+                    sb.append(s).append(" ")
                 }
-                val s = if (a < 16) {
-                    "0${a.toString(16)}"
-                } else {
-                    a.toString(16)
-                }
-                print("$s ")
-                sb.append(s).append(" ")
+                sb.deleteCharAt(sb.length - 1)
+
+                str = sb.toString()
             }
-            sb.deleteCharAt(sb.length - 1)
-        }
-        val str = sb.toString()
-        if (str.isNotEmpty()) {
-            messageManager.dealStringMsg(str, ctx)
+            is String -> str = msg
         }
 
+        println(str)
+
+        if (str.isNotEmpty()) {
+            processor.dealStringMsg(str, ctx)
+        }
     }
 
     override fun channelReadComplete(ctx: ChannelHandlerContext?) {
@@ -66,7 +67,7 @@
     }
 
     override fun channelInactive(ctx: ChannelHandlerContext?) {
-        println("------${TAG}绔彛鏈塈P涓嶆椿鍔細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
+        println("------銆�${processor.tag}銆戠鍙f湁IP涓嶆椿鍔細[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
         super.channelInactive(ctx)
     }
 
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt
index 3a44958..47017e0 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt
@@ -1,10 +1,9 @@
 package com.flightfeather.uav.socket
 
-import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
+import com.flightfeather.uav.socket.decoder.DataPackageDecoder
 import io.netty.buffer.ByteBuf
 import io.netty.channel.ChannelHandlerContext
 import io.netty.handler.codec.ByteToMessageDecoder
-import java.lang.StringBuilder
 
 /**
  * @author riku
@@ -14,13 +13,13 @@
 class UAVByteDataDecoder : ByteToMessageDecoder() {
 
     companion object {
-        const val BASE_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
-                DataPackageDecoderImpl.DEVICE_CODE_BYTES + DataPackageDecoderImpl.DATA_LENGTH + DataPackageDecoderImpl.BCC_BYTES
+        const val BASE_LENGTH = DataPackageDecoder.HEAD_BYTES + DataPackageDecoder.COMMAND_UNIT_BYTES +
+                DataPackageDecoder.DEVICE_CODE_BYTES + DataPackageDecoder.DATA_LENGTH + DataPackageDecoder.BCC_BYTES
         const val HEAD1 = 0x01.toByte()
         const val COMMAND_1 = 0x01.toByte()
         const val COMMAND_2 = 0x01.toByte()
-        const val HEAD_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
-                DataPackageDecoderImpl.DEVICE_CODE_BYTES
+        const val HEAD_LENGTH = DataPackageDecoder.HEAD_BYTES + DataPackageDecoder.COMMAND_UNIT_BYTES +
+                DataPackageDecoder.DEVICE_CODE_BYTES
     }
 
     override fun decode(p0: ChannelHandlerContext?, p1: ByteBuf?, p2: MutableList<Any>?) {
@@ -74,14 +73,14 @@
                 //鏁版嵁鍗曞厓鐨勯暱搴�
                 val length = getDataUnitLength(it, dataList)
                 // 鍒ゆ柇璇锋眰鏁版嵁鍗曞厓鏁版嵁鍙奫LENGTH_BYTES]涓瓧鑺傜殑鏍¢獙鐮佹槸鍚﹀埌榻�
-                if (it.readableBytes() < length + DataPackageDecoderImpl.BCC_BYTES) {
+                if (it.readableBytes() < length + DataPackageDecoder.BCC_BYTES) {
                     // 杩樺師璇绘寚閽�
                     it.readerIndex(beginReader)
                     return
                 }
 
                 //璇诲彇鏁版嵁鍗曞厓鍜屾牎楠岀爜鏁版嵁
-                ByteArray(length + DataPackageDecoderImpl.BCC_BYTES).apply {
+                ByteArray(length + DataPackageDecoder.BCC_BYTES).apply {
                     it.readBytes(this)
                 }.forEach {b ->
                     dataList.add(b)
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt b/src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt
index 699f09e..c9d98ea 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt
@@ -1,11 +1,14 @@
 package com.flightfeather.uav.socket
 
+import com.flightfeather.uav.socket.processor.BaseProcessor
 import io.netty.bootstrap.ServerBootstrap
+import io.netty.channel.ChannelHandler
 import io.netty.channel.ChannelInitializer
 import io.netty.channel.ChannelOption
 import io.netty.channel.nio.NioEventLoopGroup
 import io.netty.channel.socket.nio.NioServerSocketChannel
 import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.LineBasedFrameDecoder
 import io.netty.handler.codec.string.StringDecoder
 import io.netty.handler.codec.string.StringEncoder
 import java.nio.charset.Charset
@@ -19,8 +22,12 @@
     private val bossGroup = NioEventLoopGroup()
     private val workerGroup = NioEventLoopGroup()
 
-    fun startServer(port: Int) {
-        initialize()?.bind(port)?.sync()
+    fun startUnderwayServer(port: Int, processor: BaseProcessor) {
+        underwayServer(processor)?.bind(port)?.sync()
+    }
+
+    fun startElectricServer(port: Int, processor: BaseProcessor) {
+        electricServer(processor)?.bind(port)?.sync()
     }
 
     fun stopServer() {
@@ -28,28 +35,44 @@
         workerGroup.shutdownGracefully()
     }
 
-    private fun initialize(): ServerBootstrap? {
-
+    private fun newServer(childHandler: ChannelHandler): ServerBootstrap? {
         try {
             return ServerBootstrap()
-                    .group(bossGroup, workerGroup)
-                    .channel(NioServerSocketChannel::class.java)
-                    .option(ChannelOption.SO_BACKLOG, 128)
-                    .childOption(ChannelOption.SO_KEEPALIVE, true)
-                    .childOption(ChannelOption.TCP_NODELAY, true)
-                    .childHandler(object : ChannelInitializer<NioSocketChannel>() {
-                        override fun initChannel(p0: NioSocketChannel?) {
-                            p0?.pipeline()
-//                                    ?.addLast("decoder", StringDecoder())
-                                    ?.addLast(UAVByteDataDecoder())
-                                    ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
-                                    ?.addLast(ServerHandler())
-                        }
-                    })
+                .group(bossGroup, workerGroup)
+                .channel(NioServerSocketChannel::class.java)
+                .option(ChannelOption.SO_BACKLOG, 128)
+                .childOption(ChannelOption.SO_KEEPALIVE, true)
+                .childOption(ChannelOption.TCP_NODELAY, true)
+                .childHandler(childHandler)
         } catch (e: Throwable) {
             e.printStackTrace()
         }
 
         return null
     }
+
+    /**
+     * 鐢ㄧ數閲忔湇鍔$
+     */
+    private fun electricServer(processor: BaseProcessor): ServerBootstrap? = newServer(object : ChannelInitializer<NioSocketChannel>() {
+        override fun initChannel(p0: NioSocketChannel?) {
+            p0?.pipeline()
+                ?.addLast("lineDecoder", LineBasedFrameDecoder(1024))
+                ?.addLast("stringDecoder", StringDecoder())
+                ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
+                ?.addLast(ServerHandler(processor))
+        }
+    })
+
+    /**
+     * 澶氬弬鏁拌蛋鑸湇鍔$
+     */
+    private fun underwayServer(processor: BaseProcessor):ServerBootstrap? = newServer(object : ChannelInitializer<NioSocketChannel>() {
+        override fun initChannel(p0: NioSocketChannel?) {
+            p0?.pipeline()
+                ?.addLast(UAVByteDataDecoder())
+                ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
+                ?.addLast(ServerHandler(processor))
+        }
+    })
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt b/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt
new file mode 100644
index 0000000..18b2b45
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt
@@ -0,0 +1,4 @@
+package com.flightfeather.uav.socket.bean
+
+open class BaseDataPackage {
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt b/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt
new file mode 100644
index 0000000..7d5c4d1
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt
@@ -0,0 +1,87 @@
+package com.flightfeather.uav.socket.bean
+
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2020/9/10
+ */
+open class BaseMessage {
+
+    var head: String = ""
+    var length: String = ""
+
+    var qn: String = ""
+    var st: String = ""
+    var cn: String = ""
+    var pw: String = ""
+    var mn: String = ""
+    var flag: String = ""
+    var cp: String = ""
+    var extra: String = ""
+
+    var crc: String = ""
+
+    open fun newMessage() {
+        head = "##"
+        qn = SimpleDateFormat("yyyyMMddHHmmssSSS", Locale.getDefault()).format(Date())
+    }
+
+    fun parse2Str():String {
+        val str = "QN=$qn;ST=$st;CN=$cn;PW=$pw;MN=$mn;Flag=$flag;CP=&&${cp}&&$extra"
+        return "$head${getLength(str.length)}$str${getCrc(str.toByteArray(), str.length)}\r\n"
+    }
+
+    /**
+     * crc璁$畻宸ュ叿绫�
+     * @param bufData 鏁版嵁娈靛瓧绗︿覆杞寲鐨刡yte[],
+     * @param bufLen 鐨勯暱搴�
+     * @return CRC鐮侊細4瀛楄妭
+     */
+    fun getCrc(bufData: ByteArray, bufLen: Int): String? {
+        var crc = 0x0000ffff
+        val polynomial = 0x0000a001
+        var j: Int
+        if (bufLen == 0) {
+            return null
+        }
+        var i: Int = 0
+        while (i < bufLen) {
+            crc = crc xor (bufData[i].toInt() and 0x000000ff)
+            j = 0
+            while (j < 8) {
+                if (crc and 0x00000001 != 0) {
+                    crc = crc shr 1
+                    crc = crc xor polynomial
+                } else {
+                    crc = crc shr 1
+                }
+                j++
+            }
+            i++
+        }
+        var strCRC = Integer.toHexString(crc).toString()
+        if (strCRC.length < 4) {
+            strCRC += "0"
+        }
+        return strCRC
+    }
+
+    fun getLength(length: Int): String {
+        val size = StringBuilder()
+        when {
+            length >= 100 -> {
+                size.append("0")
+            }
+            length >= 10 -> {
+                size.append("00")
+            }
+            length >= 0 -> {
+                size.append("000")
+            }
+        }
+        size.append(length)
+        return size.toString()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt b/src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt
new file mode 100644
index 0000000..129d4c4
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt
@@ -0,0 +1,16 @@
+package com.flightfeather.uav.socket.bean
+
+import java.util.*
+
+class ElectricMessage : BaseMessage() {
+    var dataTime: Date? = null
+    var electricityA: Double = -1.0
+    var electricityB: Double = -1.0
+    var electricityC: Double = -1.0
+    var voltageA: Double = -1.0
+    var voltageB: Double = -1.0
+    var voltageC: Double = -1.0
+    var powerA: Double = -1.0
+    var powerB: Double = -1.0
+    var powerC: Double = -1.0
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt
index eee55d6..12e53d0 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt
@@ -1,7 +1,6 @@
 package com.flightfeather.uav.socket.decoder
 
 import com.flightfeather.uav.socket.bean.AirDataPackage
-import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
 
 /**
  * 绌烘皵璐ㄩ噺澶氬弬鏁版暟鎹В鐮佸櫒
@@ -29,7 +28,7 @@
             }
     }
 
-    private val dataPackageDecoder: DataPackageDecoder = DataPackageDecoderImpl()
+    private val dataPackageDecoder: DataPackageDecoder = DataPackageDecoder()
 
     fun decode(msg: String): AirDataPackage {
         val list = dataPackageDecoder.toStringList(msg)
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt
new file mode 100644
index 0000000..d7f40d0
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt
@@ -0,0 +1,109 @@
+package com.flightfeather.uav.socket.decoder
+
+import com.flightfeather.uav.common.utils.CommonUtil
+import com.flightfeather.uav.socket.bean.BaseMessage
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * @author riku
+ * Date: 2020/9/10
+ */
+typealias Decode<T> = (m: T, s: String) -> Unit
+
+abstract class BaseDataDecoder<T : BaseMessage> {
+
+    companion object {
+        const val INVALID_VALUE = -1.0
+    }
+
+    private var isInit = false
+
+    private lateinit var message: T
+
+    abstract fun messageClass(): Class<T>
+
+    abstract fun getCpDecode(): List<Decode<T>>
+
+    private val decodeList = mutableListOf<Decode<T>>()
+
+    private val getHead: Decode<T> = {m, s ->
+        m.head = s.substring(0, 2)
+    }
+
+    private val getLength: Decode<T> = {m, s ->
+        m.length = s.substring(2, 6)
+    }
+
+    private val getQN: Decode<T> = {m, s ->
+        m.qn = getData(s, "QN=", ";")
+    }
+
+    private val getST: Decode<T> = {m, s ->
+        m.st = getData(s, "ST=", ";")
+    }
+
+    private val getCN: Decode<T> = {m, s ->
+        m.cn = getData(s, "CN=", ";")
+    }
+
+    private val getPW: Decode<T> = {m, s ->
+        m.pw = getData(s, "PW=", ";")
+    }
+
+    private val getMN: Decode<T> = {m, s ->
+        m.mn = getData(s, "MN=", ";")
+    }
+
+    private val getCP: Decode<T> = {m, s ->
+        m.cp = getData(s, "CP=&&", "&&")
+    }
+
+    private val getExtra:Decode<T> = {m, s ->
+        val start = s.lastIndexOf("&&")
+        val end = s.length - 4
+        m.extra = s.substring(start, end).substring(2)
+    }
+
+
+    private val getCrc: Decode<T> = {m, s ->
+        m.crc = s.substring(s.length - 4, s.length)
+    }
+
+    protected fun getData(msg: String, start: String, end: String) =
+            CommonUtil.getSubStr(msg, start, end)?.substring(start.length) ?: ""
+
+    private fun init() {
+        if (!isInit) {
+
+            decodeList.add(getHead)
+            decodeList.add(getLength)
+            decodeList.add(getQN)
+            decodeList.add(getST)
+            decodeList.add(getCN)
+            decodeList.add(getPW)
+            decodeList.add(getMN)
+            decodeList.add(getCP)
+            decodeList.add(getExtra)
+            decodeList.add(getCrc)
+
+            decodeList.addAll(this.getCpDecode())
+
+            isInit = true
+        }
+        message = this.messageClass().newInstance()
+    }
+
+    fun decode(msg: String): T {
+        init()
+
+        decodeList.forEach {
+            try {
+                it.invoke(message, msg)
+            } catch (e: Exception) {
+                println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}: 鍛戒护鏃犳硶鑾峰彇[${it.javaClass.name}]")
+            }
+        }
+        return message
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt
index 8740c9c..27149c5 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt
@@ -16,22 +16,103 @@
  * 2                   鏁版嵁鍗曞厓闀垮害
  * 鍊掓暟绗�2           鏍¢獙鐮�
  */
-interface DataPackageDecoder {
+class DataPackageDecoder {
 
-    fun getHead(b: List<String>): String?
+    companion object {
+        //        鏁版嵁澶�
+        const val HEAD_BYTES = 1
+        //        鐩戞祴鍙傛暟纭鎸囦护浣�
+        const val COMMAND_UNIT_BYTES = 1
+        //        璁惧绫诲瀷
+        const val DEVICE_CODE_BYTES = 6
+        //        鏈鐩戞祴鐨勭┖姘斿洜瀛愭暟閲�
+        const val DATA_LENGTH = 1
+        //        鏍¢獙
+        const val BCC_BYTES = 2
+    }
 
-    fun getCommandUnit(b: List<String>): Int?
+    private val dataUnitDecoder: DataUnitDecoder = DataUnitDecoder()
 
-    fun getDeviceCode(b: List<String>): String?
 
-    fun getDataTime(b: List<String>): Date
+    fun getHead(b: List<String>): String? {
+        return if (b.isNotEmpty()) {
+            val s = StringBuilder()
+            repeat(HEAD_BYTES) {
+                s.append(b[it])
+            }
+            s.toString()
+        } else {
+            null
+        }
+    }
 
-    fun getDataLength(b: List<String>): Int
+    fun getCommandUnit(b: List<String>): Int? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES)) {
+        val s = StringBuilder()
+        repeat(COMMAND_UNIT_BYTES) {
+            s.append(b[HEAD_BYTES + it])
+        }
+        s.toString().toIntOrNull(16)
+    } else {
+        null
+    }
 
-    fun getDataUnit(b: List<String>): List<DataUnit>
+    fun getDeviceCode(b: List<String>): String? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES)) {
+        //2021/1/7 '0A'浠h〃杞﹁浇璁惧锛�'0B'浠h〃鏃犱汉鏈鸿澶囷紝'0C'涓虹綉鏍煎寲鐩戞祴
+        val s = StringBuilder()
+        repeat(DEVICE_CODE_BYTES) {
+            s.append(b[HEAD_BYTES + COMMAND_UNIT_BYTES + it])
+        }
+        s.toString()
+    } else {
+        null
+    }
 
-    fun getCheckCode(b: List<String>): Int?
+    fun getDataTime(b: List<String>): Date {
+        // FIXME: 2021/1/7 閲囨牱鏃堕棿鍜岀洃娴嬪洜瀛愪竴鍚屾斁鍦ㄤ簡鏁版嵁閮ㄥ垎锛屾澶勪笉鍐嶅仛瑙f瀽
+        return Date()
+    }
 
-    fun toStringList(msg: String): List<String>
+    fun getDataLength(b: List<String>): Int {
+        if (b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) return 0
+
+        val hexNum = b[HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES]
+
+        return hexNum.toIntOrNull(16) ?: 0
+    }
+
+    fun getDataUnit(b: List<String>): List<DataUnit> {
+        if (getDataLength(b) == 0 || b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) {
+            return emptyList()
+        }
+
+        val unit = mutableListOf<String>()
+        val start = HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH
+        for (i in start..b.size - 1 - BCC_BYTES) {
+            unit.add(b[i])
+        }
+
+        dataUnitDecoder.run {
+            return when (getCommandUnit(b)) {
+                AirCommandUnit.Confirm.value -> getAirConfirmData(unit, getDeviceCode(b))
+                AirCommandUnit.AirData.value -> getAirData(unit, getDeviceCode(b))
+                else -> emptyList()
+            }
+        }
+    }
+
+    fun getCheckCode(b: List<String>): Int? {
+        return if (b.size >= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + BCC_BYTES) {
+            val hexNum = "${b[b.size - 2]}${b[b.size - 1]}"
+
+            hexNum.toIntOrNull(16)
+        } else {
+            null
+        }
+    }
+
+    fun toStringList(msg: String): List<String> {
+        return msg.split(" ")
+    }
+
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt
index 0975dd8..6b848c4 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt
@@ -2,6 +2,9 @@
 
 import com.flightfeather.uav.socket.bean.*
 import com.flightfeather.uav.socket.eunm.AirCommandUnit
+import com.flightfeather.uav.socket.eunm.FactorType
+import org.slf4j.LoggerFactory
+import java.text.SimpleDateFormat
 import java.util.*
 
 /**
@@ -12,10 +15,160 @@
  * 鏁版嵁鍗曞厓鎸夌収鍛戒护鍗曞厓鐨勭被鍨嬪叡鏈変互涓嬪嚑绉嶇被鍨嬶細
  * 鍛戒护鍗曞厓 @see [AirCommandUnit]
  */
-interface DataUnitDecoder {
+class DataUnitDecoder {
 
-    fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData>
+    private val logger = LoggerFactory.getLogger(javaClass.name)
 
-    fun getAirData(b: List<String>, deviceCode: String?): List<AirData>
+    private val types = mutableMapOf<String?, MutableList<AirTypeData>>()
+
+    fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData> {
+        val resultList = mutableListOf<AirTypeData>()
+        b.forEach {
+            FactorType.getByIndex(it.toInt(16))?.let { f->
+                resultList.add(AirTypeData(f))
+            }
+        }
+        if (!types.containsKey(deviceCode)) {
+            types[deviceCode] = mutableListOf()
+        }
+        types[deviceCode]?.clear()
+        types[deviceCode]?.addAll(resultList)
+
+        return resultList
+    }
+
+    fun getAirData(b: List<String>, deviceCode: String?): List<AirData> {
+        val resultList = mutableListOf<AirData>()
+
+        if (!types.containsKey(deviceCode)) {
+            return resultList
+        }
+
+        var i = 0
+        types[deviceCode]?.forEach {
+            if (i > b.size - it.factorType.byteLength) {
+                return@forEach
+            }
+
+            when (it.factorType) {
+                FactorType.LNG -> {
+                    val valid = b[i].toInt(16).toChar()//缁忕含搴︽槸鍚︽湁鏁堬紙鏈夋晥: A; 鏃犳晥: V锛�
+
+                    //缁忕含搴﹀師濮嬪�硷紝渚嬶細121掳30.0411鈥诧紝鍏朵腑 121 瀵瑰簲a1锛�30瀵瑰簲b1锛�04瀵瑰簲b2锛�11瀵瑰簲b3
+                    val a1 = b[i + 1].toInt(16)//搴�
+                    val b1 = b[i + 2].toInt(16)//鍒嗭紙鏁存暟锛�
+                    var b2 = b[i + 3].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍓嶄袱浣嶏級
+                    var b3 = b[i + 4].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍚庝袱浣嶏級
+
+//                    var b2 = "${b[i + 3]}${b[i + 4]}".toInt(16).toDouble()
+                    b2 /= 100
+                    b3 /= 10000
+                    val lng = a1 + (b1 + b2 + b3) / 60
+                    val s = b[i + 5].toInt(16).toChar()
+
+                    resultList.add(AirData().apply {
+                        factorId = it.factorType.value?.toString()
+                        factorName = it.factorType.des
+                        factorData = lng
+                        statusList = listOf(valid.toString(), s.toString())
+                    })
+                }
+                FactorType.LAT -> {
+                    val a1 = b[i].toInt(16)
+                    val b1 = b[i + 1].toInt(16)
+                    var b2 = b[i + 2].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍓嶄袱浣嶏級
+                    var b3 = b[i + 3].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍚庝袱浣嶏級
+
+                    b2 /= 100
+                    b3 /= 10000
+                    val lat = a1 + (b1 + b2 + b3) / 60
+                    val s = b[i + 4].toInt(16).toChar()
+                    resultList.add(AirData().apply {
+                        factorId = it.factorType.value.toString()
+                        factorName = it.factorType.des
+                        factorData = lat
+                        statusList = listOf(s.toString())
+                    })
+                }
+                FactorType.TIME -> {
+                    val year = b[i].toInt(16).toString().run { numberFormat(this) }
+                    val month = b[i + 1].toInt(16).toString().run { numberFormat(this) }
+                    val day = b[i + 2].toInt(16).toString().run { numberFormat(this) }
+                    val hour = b[i + 3].toInt(16).toString().run { numberFormat(this) }
+                    val minute = b[i + 4].toInt(16).toString().run { numberFormat(this) }
+                    val second = b[i + 5].toInt(16).toString().run { numberFormat(this) }
+                    val date = "20$year-$month-$day $hour:$minute:$second"
+                    val time = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date).time
+                    resultList.add(AirData().apply {
+                        factorId = it.factorType.value.toString()
+                        factorName = it.factorType.des
+                        factorData = time.toDouble()
+                        statusList = listOf(date)
+                    })
+                }
+                else -> {
+                    when (it.factorType.byteLength) {
+                        AirDataPackage.FACTOR_BIT_LENGTH_2 -> {
+                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
+                            var b1 = b[i + 2].toInt(16).toDouble()
+                            while (b1 >= 1) {
+                                b1 /= 10
+                            }
+                            val data1 = a1 + b1
+
+                            resultList.add(AirData().apply {
+                                factorId = it.factorType.value?.toString()
+                                factorName = it.factorType.des
+                                factorData = data1
+                            })
+                        }
+                        AirDataPackage.FACTOR_BIT_LENGTH_1 -> {
+                            //鏁版嵁瀹為檯鍊硷紙3浣嶅瓧鑺傝〃绀猴級
+                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
+                            var b1 = b[i + 2].toInt(16).toDouble()
+                            while (b1 >= 1) {
+                                b1 /= 10
+                            }
+                            val data1 = a1 + b1
+
+                            //鏁版嵁鐗╃悊閲忥紙3浣嶅瓧鑺傝〃绀猴級
+                            val a2 = "${b[i+3]}${b[i + 4]}".toInt(16)
+                            var b2 = b[i + 5].toInt(16).toDouble()
+                            while (b2 >= 1) {
+                                b2 /= 10
+                            }
+                            val data2 = a2 + b2
+
+                            resultList.add(AirData().apply {
+                                factorId = it.factorType.value?.toString()
+                                factorName = it.factorType.des
+                                factorData = data1
+                                physicalQuantity = data2
+                            })
+                        }
+                        AirDataPackage.FACTOR_BIT_LENGTH_3 -> {
+                            val data = "${b[i]}${b[i + 1]}".toInt(16)
+                            resultList.add(AirData().apply {
+                                factorId = it.factorType.value.toString()
+                                factorName = it.factorType.des
+                                factorData = data.toDouble()
+                            })
+                        }
+                    }
+                }
+            }
+
+            i += it.factorType.byteLength
+        }
+
+        return resultList
+    }
+
+    private fun numberFormat(num: String) =
+        if (num.length < 2) {
+            "0$num"
+        } else {
+            num
+        }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt
new file mode 100644
index 0000000..35232d5
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt
@@ -0,0 +1,85 @@
+package com.flightfeather.uav.socket.decoder
+
+import com.flightfeather.uav.common.utils.DateUtil
+import com.flightfeather.uav.socket.bean.ElectricMessage
+import org.springframework.stereotype.Component
+
+@Component
+class ElectricDataDecoder:BaseDataDecoder<ElectricMessage>() {
+    private val dateUtil = DateUtil()
+
+    override fun messageClass(): Class<ElectricMessage> = ElectricMessage::class.java
+
+    override fun getCpDecode(): List<Decode<ElectricMessage>> = listOf(
+        getDataTime,
+        getElectricityA, getElectricityB, getElectricityC,
+        getVoltageA, getVoltageB, getVoltageC,
+        getPowerA, getPowerB, getPowerC
+    )
+
+    private val getDataTime: Decode<ElectricMessage> = { e, s ->
+        val time = getData(s, "DataTime=", ";")
+        time.let {
+            val date = if (it.length > "yyyyMMddHHmmss".length) {
+                dateUtil.StringToDate(it, "yyyyMMddHHmmssSSS")
+            } else {
+                dateUtil.StringToDate(it, "yyyyMMddHHmmss")
+            }
+            e.dataTime = date
+        }
+    }
+
+    private val getElectricityA: Decode<ElectricMessage> = { e, s ->
+        getData(s, "550-Rtd=", ";").let {
+            e.electricityA = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getElectricityB: Decode<ElectricMessage> = { e, s ->
+        getData(s, "551-Rtd=", ";").let {
+            e.electricityB = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getElectricityC: Decode<ElectricMessage> = { e, s ->
+        getData(s, "552-Rtd=", ";").let {
+            e.electricityC = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getVoltageA: Decode<ElectricMessage> = { e, s ->
+        getData(s, "553-Rtd=", ";").let {
+            e.voltageA = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getVoltageB: Decode<ElectricMessage> = { e, s ->
+        getData(s, "554-Rtd=", ";").let {
+            e.voltageB = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getVoltageC: Decode<ElectricMessage> = { e, s ->
+        getData(s, "555-Rtd=", ";").let {
+            e.voltageC = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getPowerA: Decode<ElectricMessage> = { e, s ->
+        getData(s, "556-Rtd=", ";").let {
+            e.powerA = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getPowerB: Decode<ElectricMessage> = { e, s ->
+        getData(s, "557-Rtd=", ";").let {
+            e.powerB = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+
+    private val getPowerC: Decode<ElectricMessage> = { e, s ->
+        getData(s, "558-Rtd=", ";").let {
+            e.powerC = it.toDoubleOrNull() ?: INVALID_VALUE
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt
deleted file mode 100644
index e79b6c0..0000000
--- a/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.flightfeather.uav.socket.decoder.impl
-
-import com.flightfeather.uav.socket.bean.DataUnit
-import com.flightfeather.uav.socket.decoder.DataPackageDecoder
-import com.flightfeather.uav.socket.decoder.DataUnitDecoder
-import com.flightfeather.uav.socket.eunm.AirCommandUnit
-import java.util.*
-import kotlin.text.StringBuilder
-
-/**
- * @author riku
- * Date: 2019/9/12
- */
-class DataPackageDecoderImpl : DataPackageDecoder {
-
-    companion object {
-//        鏁版嵁澶�
-        const val HEAD_BYTES = 1
-//        鐩戞祴鍙傛暟纭鎸囦护浣�
-        const val COMMAND_UNIT_BYTES = 1
-//        璁惧绫诲瀷
-        const val DEVICE_CODE_BYTES = 6
-//        鏈鐩戞祴鐨勭┖姘斿洜瀛愭暟閲�
-        const val DATA_LENGTH = 1
-//        鏍¢獙
-        const val BCC_BYTES = 2
-    }
-
-    private val dataUnitDecoder: DataUnitDecoder = DataUnitDecoderImpl()
-
-
-    override fun getHead(b: List<String>): String? {
-        return if (b.isNotEmpty()) {
-            val s = StringBuilder()
-            repeat(HEAD_BYTES) {
-                s.append(b[it])
-            }
-            s.toString()
-        } else {
-            null
-        }
-    }
-
-    override fun getCommandUnit(b: List<String>): Int? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES)) {
-        val s = StringBuilder()
-        repeat(COMMAND_UNIT_BYTES) {
-            s.append(b[HEAD_BYTES + it])
-        }
-        s.toString().toIntOrNull(16)
-    } else {
-        null
-    }
-
-    override fun getDeviceCode(b: List<String>): String? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES)) {
-        //2021/1/7 '0A'浠h〃杞﹁浇璁惧锛�'0B'浠h〃鏃犱汉鏈鸿澶囷紝'0C'涓虹綉鏍煎寲鐩戞祴
-        val s = StringBuilder()
-        repeat(DEVICE_CODE_BYTES) {
-            s.append(b[HEAD_BYTES + COMMAND_UNIT_BYTES + it])
-        }
-        s.toString()
-    } else {
-        null
-    }
-
-    override fun getDataTime(b: List<String>): Date {
-        // FIXME: 2021/1/7 閲囨牱鏃堕棿鍜岀洃娴嬪洜瀛愪竴鍚屾斁鍦ㄤ簡鏁版嵁閮ㄥ垎锛屾澶勪笉鍐嶅仛瑙f瀽
-        return Date()
-    }
-
-    override fun getDataLength(b: List<String>): Int {
-        if (b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) return 0
-
-        val hexNum = b[HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES]
-
-        return hexNum.toIntOrNull(16) ?: 0
-    }
-
-    override fun getDataUnit(b: List<String>): List<DataUnit> {
-        if (getDataLength(b) == 0 || b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) {
-            return emptyList()
-        }
-
-        val unit = mutableListOf<String>()
-        val start = HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH
-        for (i in start..b.size - 1 - BCC_BYTES) {
-            unit.add(b[i])
-        }
-
-        dataUnitDecoder.run {
-            return when (getCommandUnit(b)) {
-                AirCommandUnit.Confirm.value -> getAirConfirmData(unit, getDeviceCode(b))
-                AirCommandUnit.AirData.value -> getAirData(unit, getDeviceCode(b))
-                else -> emptyList()
-            }
-        }
-    }
-
-    override fun getCheckCode(b: List<String>): Int? {
-        return if (b.size >= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + BCC_BYTES) {
-            val hexNum = "${b[b.size - 2]}${b[b.size - 1]}"
-
-            hexNum.toIntOrNull(16)
-        } else {
-            null
-        }
-    }
-
-    override fun toStringList(msg: String): List<String> {
-        return msg.split(" ")
-    }
-
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt b/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt
deleted file mode 100644
index 3290fa7..0000000
--- a/src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-package com.flightfeather.uav.socket.decoder.impl
-
-import com.flightfeather.uav.socket.bean.AirData
-import com.flightfeather.uav.socket.bean.AirDataPackage
-import com.flightfeather.uav.socket.bean.AirTypeData
-import com.flightfeather.uav.socket.decoder.DataUnitDecoder
-import com.flightfeather.uav.socket.eunm.FactorType
-import org.slf4j.LoggerFactory
-import java.text.SimpleDateFormat
-
-/**
- * @author riku
- * Date: 2019/9/15
- */
-class DataUnitDecoderImpl : DataUnitDecoder {
-
-    private val logger = LoggerFactory.getLogger(javaClass.name)
-
-    private val types = mutableMapOf<String?, MutableList<AirTypeData>>()
-
-    override fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData> {
-        val resultList = mutableListOf<AirTypeData>()
-        b.forEach {
-            FactorType.getByIndex(it.toInt(16))?.let { f->
-                resultList.add(AirTypeData(f))
-            }
-        }
-        if (!types.containsKey(deviceCode)) {
-            types[deviceCode] = mutableListOf()
-        }
-        types[deviceCode]?.clear()
-        types[deviceCode]?.addAll(resultList)
-
-        return resultList
-    }
-
-    override fun getAirData(b: List<String>, deviceCode: String?): List<AirData> {
-        val resultList = mutableListOf<AirData>()
-
-        if (!types.containsKey(deviceCode)) {
-            return resultList
-        }
-
-        var i = 0
-        types[deviceCode]?.forEach {
-            if (i > b.size - it.factorType.byteLength) {
-                return@forEach
-            }
-
-            when (it.factorType) {
-                FactorType.LNG -> {
-                    val valid = b[i].toInt(16).toChar()//缁忕含搴︽槸鍚︽湁鏁堬紙鏈夋晥: A; 鏃犳晥: V锛�
-
-                    //缁忕含搴﹀師濮嬪�硷紝渚嬶細121掳30.0411鈥诧紝鍏朵腑 121 瀵瑰簲a1锛�30瀵瑰簲b1锛�04瀵瑰簲b2锛�11瀵瑰簲b3
-                    val a1 = b[i + 1].toInt(16)//搴�
-                    val b1 = b[i + 2].toInt(16)//鍒嗭紙鏁存暟锛�
-                    var b2 = b[i + 3].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍓嶄袱浣嶏級
-                    var b3 = b[i + 4].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍚庝袱浣嶏級
-
-//                    var b2 = "${b[i + 3]}${b[i + 4]}".toInt(16).toDouble()
-                    b2 /= 100
-                    b3 /= 10000
-                    val lng = a1 + (b1 + b2 + b3) / 60
-                    val s = b[i + 5].toInt(16).toChar()
-
-                    resultList.add(AirData().apply {
-                        factorId = it.factorType.value?.toString()
-                        factorName = it.factorType.des
-                        factorData = lng
-                        statusList = listOf(valid.toString(), s.toString())
-                    })
-                }
-                FactorType.LAT -> {
-                    val a1 = b[i].toInt(16)
-                    val b1 = b[i + 1].toInt(16)
-                    var b2 = b[i + 2].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍓嶄袱浣嶏級
-                    var b3 = b[i + 3].toInt(16).toDouble()//鍒嗭紙灏忔暟閮ㄥ垎鍚庝袱浣嶏級
-
-                    b2 /= 100
-                    b3 /= 10000
-                    val lat = a1 + (b1 + b2 + b3) / 60
-                    val s = b[i + 4].toInt(16).toChar()
-                    resultList.add(AirData().apply {
-                        factorId = it.factorType.value.toString()
-                        factorName = it.factorType.des
-                        factorData = lat
-                        statusList = listOf(s.toString())
-                    })
-                }
-                FactorType.TIME -> {
-                    val year = b[i].toInt(16).toString().run { numberFormat(this) }
-                    val month = b[i + 1].toInt(16).toString().run { numberFormat(this) }
-                    val day = b[i + 2].toInt(16).toString().run { numberFormat(this) }
-                    val hour = b[i + 3].toInt(16).toString().run { numberFormat(this) }
-                    val minute = b[i + 4].toInt(16).toString().run { numberFormat(this) }
-                    val second = b[i + 5].toInt(16).toString().run { numberFormat(this) }
-                    val date = "20$year-$month-$day $hour:$minute:$second"
-                    val time = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date).time
-                    resultList.add(AirData().apply {
-                        factorId = it.factorType.value.toString()
-                        factorName = it.factorType.des
-                        factorData = time.toDouble()
-                        statusList = listOf(date)
-                    })
-                }
-                else -> {
-                    when (it.factorType.byteLength) {
-                        AirDataPackage.FACTOR_BIT_LENGTH_2 -> {
-                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
-                            var b1 = b[i + 2].toInt(16).toDouble()
-                            while (b1 >= 1) {
-                                b1 /= 10
-                            }
-                            val data1 = a1 + b1
-
-                            resultList.add(AirData().apply {
-                                factorId = it.factorType.value?.toString()
-                                factorName = it.factorType.des
-                                factorData = data1
-                            })
-                        }
-                        AirDataPackage.FACTOR_BIT_LENGTH_1 -> {
-                            //鏁版嵁瀹為檯鍊硷紙3浣嶅瓧鑺傝〃绀猴級
-                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
-                            var b1 = b[i + 2].toInt(16).toDouble()
-                            while (b1 >= 1) {
-                                b1 /= 10
-                            }
-                            val data1 = a1 + b1
-
-                            //鏁版嵁鐗╃悊閲忥紙3浣嶅瓧鑺傝〃绀猴級
-                            val a2 = "${b[i+3]}${b[i + 4]}".toInt(16)
-                            var b2 = b[i + 5].toInt(16).toDouble()
-                            while (b2 >= 1) {
-                                b2 /= 10
-                            }
-                            val data2 = a2 + b2
-
-                            resultList.add(AirData().apply {
-                                factorId = it.factorType.value?.toString()
-                                factorName = it.factorType.des
-                                factorData = data1
-                                physicalQuantity = data2
-                            })
-                        }
-                        AirDataPackage.FACTOR_BIT_LENGTH_3 -> {
-                            val data = "${b[i]}${b[i + 1]}".toInt(16)
-                            resultList.add(AirData().apply {
-                                factorId = it.factorType.value.toString()
-                                factorName = it.factorType.des
-                                factorData = data.toDouble()
-                            })
-                        }
-                    }
-                }
-            }
-
-            i += it.factorType.byteLength
-        }
-
-        return resultList
-    }
-
-    private fun numberFormat(num: String) =
-            if (num.length < 2) {
-                "0$num"
-            } else {
-                num
-            }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt b/src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt
new file mode 100644
index 0000000..380981a
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt
@@ -0,0 +1,24 @@
+package com.flightfeather.uav.socket.processor
+
+import com.flightfeather.uav.common.utils.FileUtil
+import com.flightfeather.uav.socket.DeviceSession
+import io.netty.channel.ChannelHandlerContext
+import java.text.SimpleDateFormat
+import java.util.*
+
+abstract class BaseProcessor {
+
+    abstract var tag: String
+
+    val deviceSession = DeviceSession()
+
+    abstract fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?)
+
+    /**
+     * 淇濆瓨鑷硉xt鏂囨湰
+     */
+    fun saveToTxt(msg: String) {
+        val data = "[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]data=> $msg"
+        FileUtil.instance?.saveObdData(data)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt b/src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt
new file mode 100644
index 0000000..4d5f655
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt
@@ -0,0 +1,48 @@
+package com.flightfeather.uav.socket.processor
+
+import com.flightfeather.uav.repository.ElectricRepository
+import com.flightfeather.uav.socket.bean.BaseMessage
+import com.flightfeather.uav.socket.bean.ElectricMessage
+import com.flightfeather.uav.socket.decoder.ElectricDataDecoder
+import io.netty.channel.ChannelHandlerContext
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Component
+import javax.annotation.PostConstruct
+
+/**
+ * 澶勭悊鐢ㄧ數閲弒ocket鎺ユ敹鐨勬秷鎭�
+ * @author riku
+ */
+@Component
+class ElectricProcessor() : BaseProcessor() {
+    companion object {
+        private lateinit var instance: ElectricProcessor
+    }
+
+    @Autowired
+    lateinit var electricRepository: ElectricRepository
+
+    @Autowired
+    lateinit var electricDataDecoder: ElectricDataDecoder
+
+    @PostConstruct
+    fun init() {
+        instance = this
+    }
+
+    override var tag: String = "鐢ㄧ數閲�"
+
+    override fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
+        //瑙e寘
+        val packageData = electricDataDecoder.decode(msg)
+        deviceSession.saveDevice(packageData.mn, ctx)
+        saveToTxt(msg)
+        saveToDataBase(packageData, msg)
+    }
+
+    private fun saveToDataBase(message: BaseMessage, msg: String) {
+        if (message is ElectricMessage) {
+            instance.electricRepository.saveData(message)
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt b/src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
similarity index 73%
rename from src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt
rename to src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
index 4f153e3..33a5861 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
@@ -1,10 +1,9 @@
-package com.flightfeather.uav.socket
+package com.flightfeather.uav.socket.processor
 
-import com.flightfeather.uav.common.utils.FileUtil
-import com.flightfeather.uav.repository.*
-import com.flightfeather.uav.socket.bean.*
+import com.flightfeather.uav.repository.AirDataRepository
+import com.flightfeather.uav.socket.bean.AirDataPackage
 import com.flightfeather.uav.socket.decoder.AirDataDecoder
-import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
+import com.flightfeather.uav.socket.decoder.DataPackageDecoder
 import com.flightfeather.uav.socket.eunm.AirCommandUnit
 import io.netty.channel.ChannelHandlerContext
 import org.springframework.beans.factory.annotation.Autowired
@@ -20,10 +19,10 @@
  */
 
 @Component
-class MessageManager{
+class UnderwayProcessor : BaseProcessor() {
 
-    companion object{
-        private lateinit var instance: MessageManager
+    companion object {
+        private lateinit var instance: UnderwayProcessor
 
         private const val TAG = "UAV"
     }
@@ -32,35 +31,27 @@
     lateinit var airDataRepository: AirDataRepository
 
     val airDataDecoder = AirDataDecoder.instance
-    val dataPackageDecoder = DataPackageDecoderImpl()
+    val dataPackageDecoder = DataPackageDecoder()
 
     @PostConstruct
     fun init() {
         instance = this
-        airDataRepository = this.airDataRepository
     }
 
-    fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
+    override var tag: String = "璧拌埅鐩戞祴"
+
+    override fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
         //瑙e寘
         val packageData = airDataDecoder.decode(msg)
 
-
         if (bccCheck(msg)) {
             //淇濆瓨
-            DeviceSession.saveDevice(packageData.deviceCode, ctx)
+            deviceSession.saveDevice(packageData.deviceCode, ctx)
             saveToTxt(msg)
             saveToDataBase(packageData)
         } else {
             println("------${TAG}鏁版嵁BCC鏍¢獙澶辫触锛岃垗寮� [${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]")
         }
-    }
-
-    /**
-     * 淇濆瓨鑷硉xt鏂囨湰
-     */
-    fun saveToTxt(msg: String) {
-        val data = "[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]data=> $msg"
-        FileUtil.instance?.saveObdData(data)
     }
 
     /**
@@ -75,7 +66,7 @@
     /**
      * BCC锛堝紓鎴栨牎楠岋級
      */
-    fun bccCheck(msg: String):Boolean {
+    fun bccCheck(msg: String): Boolean {
         val list = mutableListOf<String>().apply {
             addAll(dataPackageDecoder.toStringList(msg))
         }
@@ -97,11 +88,11 @@
     }
 
 
-    fun encodeToBytes(msg:String): ByteArray {
+    fun encodeToBytes(msg: String): ByteArray {
         val list = msg.split(" ")
         val bytes = ByteArray(list.size)
         for (i in 0 until list.size) {
-            bytes[i]=list[i].toInt(16).toByte()
+            bytes[i] = list[i].toInt(16).toByte()
         }
 
         return bytes
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 9b2cea4..b083e00 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -8,6 +8,10 @@
     url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
     username: dronemonitor
     password: dronemonitor_hackxrnomxm
+
+#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
+#    username: root
+#    password: 123456
     hikari:
       maximum-pool-size: 500
       minimum-idle: 20
diff --git a/src/main/resources/generator/generatorConfig.xml b/src/main/resources/generator/generatorConfig.xml
index 6b93357..1063179 100644
--- a/src/main/resources/generator/generatorConfig.xml
+++ b/src/main/resources/generator/generatorConfig.xml
@@ -46,6 +46,7 @@
         </javaClientGenerator>
         <!-- 瑕佺敓鎴愮殑琛� tableName鏄暟鎹簱涓殑琛ㄥ悕鎴栬鍥惧悕 domainObjectName鏄疄浣撶被鍚�-->
 <!--        <table tableName="air_real_time_data" domainObjectName="RealTimeData" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
-        <table tableName="mission" domainObjectName="Mission" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
+<!--        <table tableName="mission" domainObjectName="Mission" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
+        <table tableName="el_minutevalue" domainObjectName="ElectricMinuteValue" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
     </context>
 </generatorConfiguration>
\ No newline at end of file
diff --git a/src/main/resources/mapper/ElectricMinuteValueMapper.xml b/src/main/resources/mapper/ElectricMinuteValueMapper.xml
new file mode 100644
index 0000000..606c668
--- /dev/null
+++ b/src/main/resources/mapper/ElectricMinuteValueMapper.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.flightfeather.uav.domain.mapper.ElectricMinuteValueMapper">
+  <resultMap id="BaseResultMap" type="com.flightfeather.uav.domain.entity.ElectricMinuteValue">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="MV_ID" jdbcType="INTEGER" property="mvId" />
+    <result column="MV_Stat_Code" jdbcType="VARCHAR" property="mvStatCode" />
+    <result column="MV_Create_Time" jdbcType="TIMESTAMP" property="mvCreateTime" />
+    <result column="MV_Data_Time" jdbcType="TIMESTAMP" property="mvDataTime" />
+    <result column="MV_Electricity_A" jdbcType="DOUBLE" property="mvElectricityA" />
+    <result column="MV_Electricity_B" jdbcType="DOUBLE" property="mvElectricityB" />
+    <result column="MV_Electricity_C" jdbcType="DOUBLE" property="mvElectricityC" />
+    <result column="MV_Voltage_A" jdbcType="DOUBLE" property="mvVoltageA" />
+    <result column="MV_Voltage_B" jdbcType="DOUBLE" property="mvVoltageB" />
+    <result column="MV_Voltage_C" jdbcType="DOUBLE" property="mvVoltageC" />
+    <result column="MV_Power_A" jdbcType="DOUBLE" property="mvPowerA" />
+    <result column="MV_Power_B" jdbcType="DOUBLE" property="mvPowerB" />
+    <result column="MV_Power_C" jdbcType="DOUBLE" property="mvPowerC" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    MV_ID, MV_Stat_Code, MV_Create_Time, MV_Data_Time, MV_Electricity_A, MV_Electricity_B, 
+    MV_Electricity_C, MV_Voltage_A, MV_Voltage_B, MV_Voltage_C, MV_Power_A, MV_Power_B, 
+    MV_Power_C
+  </sql>
+</mapper>
\ No newline at end of file
diff --git a/src/test/kotlin/com/flightfeather/uav/socket/MessageManagerTest.kt b/src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt
similarity index 74%
rename from src/test/kotlin/com/flightfeather/uav/socket/MessageManagerTest.kt
rename to src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt
index 38b1810..cfa3b78 100644
--- a/src/test/kotlin/com/flightfeather/uav/socket/MessageManagerTest.kt
+++ b/src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt
@@ -1,14 +1,15 @@
 package com.flightfeather.uav.socket
 
+import com.flightfeather.uav.socket.processor.UnderwayProcessor
 import org.junit.Test
 
 /**
  * @author riku
  * Date: 2019/9/16
  */
-class MessageManagerTest {
+class UnderwayProcessorTest {
 
-    private val messageManager = MessageManager()
+    private val messageManager = UnderwayProcessor()
 
     @Test
     fun bccCheck() {

--
Gitblit v1.9.3