From 9a0527dfab1170a16b83231f172f65dc5df29e8e Mon Sep 17 00:00:00 2001
From: "Server (Shared Users)" <shmd01.iptime.org>
Date: Tue, 10 Dec 2019 10:43:54 +0000
Subject: [PATCH] test

---
 RPi_Client/CoAPthon3/coapclient.py        |   1 -
 RPi_Client/CoAPthon3/testclient.py        | 226 +++++++++++++++++
 Server_CoAP/CoAPthon3/exampleresources.py |  55 +++--
 Server_CoAP/CoAPthon3/testresource.py     | 281 ++++++++++++++++++++++
 Server_CoAP/CoAPthon3/testserver.py       | 175 ++++++++++++++
 Server_Vue_Express/backend/routes/api.js  |  12 +-
 Server_Vue_Express/backend/views/rpis.pug |   4 +-
 7 files changed, 721 insertions(+), 33 deletions(-)
 create mode 100644 RPi_Client/CoAPthon3/testclient.py
 create mode 100644 Server_CoAP/CoAPthon3/testresource.py
 create mode 100644 Server_CoAP/CoAPthon3/testserver.py

diff --git a/RPi_Client/CoAPthon3/coapclient.py b/RPi_Client/CoAPthon3/coapclient.py
index e21d620..bbe7bb6 100644
--- a/RPi_Client/CoAPthon3/coapclient.py
+++ b/RPi_Client/CoAPthon3/coapclient.py
@@ -168,7 +168,6 @@ class CoapClient():
         except KeyboardInterrupt:
             print("PutBLEInfo Stop")
             client.stop()
-
         client.stop()
 
     def mkJsonbeaconInfo(self, info): # complete
diff --git a/RPi_Client/CoAPthon3/testclient.py b/RPi_Client/CoAPthon3/testclient.py
new file mode 100644
index 0000000..bbe7bb6
--- /dev/null
+++ b/RPi_Client/CoAPthon3/testclient.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+import getopt
+import socket
+import sys
+import re, uuid
+import time
+import threading
+import json
+import bluetooth._bluetooth as bluez
+import blescan
+import _thread
+import math
+from piBeacon import BeaconEmit
+
+from coapthon.client.helperclient import HelperClient
+from coapthon.utils import parse_uri
+
+__author__ = 'Giacomo Tanganelli'
+
+class CoapClient():
+    def __init__(self): # complete
+        self.ip = "shmd01.iptime.org"
+        self.myMAC = ':'.join(re.findall('..', '%012x' % uuid.getnode()))
+        self.clearMyData()
+        self.myuuid, self.operate = self.obtainMyID()
+        if self.operate == 1: # rpNode가 이미 한 개 이상존재하는 경우
+            self._beacon = BeaconEmit()
+            self.advertiseMe()
+    
+    def clearMyData(self): # complete
+        path = "/rpNodeInfoPath"
+        
+        path = "coap://" + self.ip + path
+        host, port, path = parse_uri(path)
+        try:
+            tmp = socket.gethostbyname(host)
+            host = tmp
+        except socket.gaierror:
+            pass
+
+        client = HelperClient(server=(host, port))
+
+        try:            
+            payload = {
+                'option' : -1, #clear my data from Server
+                'rpMAC' : self.myMAC
+            }
+            response = client.put(path, json.dumps(payload))
+            print((response.pretty_print()))
+
+        except KeyboardInterrupt:
+            print("obtainMyID Stop")
+            client.stop()
+
+        client.stop()
+
+    def obtainMyID(self): # complete
+        path = "/rpNodeInfoPath"
+        
+        path = "coap://" + self.ip + path
+        host, port, path = parse_uri(path)
+        try:
+            tmp = socket.gethostbyname(host)
+            host = tmp
+        except socket.gaierror:
+            pass
+
+        client = HelperClient(server=(host, port))
+
+        try:            
+            payload = {
+                'option' : 0, #obtain rpuuid from Server
+                'rpMAC' : self.myMAC
+            }
+            response = client.put(path, json.dumps(payload))
+            print((response.pretty_print()))
+            string = json.loads(response.payload)['rpuuid']
+
+        except KeyboardInterrupt:
+            print("obtainMyID Stop")
+            client.stop()
+
+        client.stop()
+        return string, json.loads(response.payload)['operate']
+
+    def advertiseMe(self): # complete
+        seq = self.myuuid
+        length = 3
+        string =""
+        for i in range(0, len(seq), 2):
+            string += seq[i:i+2]+" " 
+        print(string)
+        print(map(''.join, zip(*[iter(seq)]*length)))
+        self._beacon.beacon_Start(string)
+
+    def calculateNodePositionAtServer(self): # complete
+        path = "/rpNodeInfoPath"
+        
+        path = "coap://" + self.ip + path
+        host, port, path = parse_uri(path)
+        try:
+            tmp = socket.gethostbyname(host)
+            host = tmp
+        except socket.gaierror:
+            pass
+
+        client = HelperClient(server=(host, port))
+
+        try:            
+            payload = {
+                'option' : 1, # obtain my position from Server.
+                'rpuuid' : self.myuuid
+            }
+            response = client.put(path, json.dumps(payload))
+            print((response.pretty_print()))
+            if json.loads(response.payload)['operate'] == 0: # Postion 계산이 불가능한 경우
+                print("impossible position calculation")
+            
+        except KeyboardInterrupt:
+            print("obtainMyID Stop")
+            client.stop()
+        client.stop()
+
+    def putBLEInfo(self):  # complete
+        dev_id = 0
+        try:
+            self.sock = bluez.hci_open_dev(dev_id)
+            print("ble thread started")
+
+        except:
+            print("error accessing bluetooth device...")
+            sys.exit(1)
+
+        blescan.hci_le_set_scan_parameters(self.sock)
+        blescan.hci_enable_le_scan(self.sock)
+
+        path = "/bleInfoPath"
+        payload = []
+        
+        path = "coap://" + self.ip + path
+        host, port, path = parse_uri(path)
+        try:
+            tmp = socket.gethostbyname(host)
+            host = tmp
+        except socket.gaierror:
+            pass
+
+        client = HelperClient(server=(host, port))
+
+        try:
+            while True :
+                payload = []
+                returnedList = blescan.parse_events(self.sock, 50)
+                for beacon in returnedList:
+                    beaconInfo = [str(x) for x in beacon.split(',') if x.strip()]
+                    if beaconInfo[1][:8] == "52528282":
+                        print("scanned : "+ str(beaconInfo))
+                        regiRelThread = threading.Thread(target = self.regiRelWithNewPi, args=([beaconInfo]))
+                        regiRelThread.start()
+                        continue
+                    jsonpayload = self.mkJsonbeaconInfo(beaconInfo)
+                    if jsonpayload['distance'] < 60:
+                        payload.append(jsonpayload)
+                
+                response = client.put(path, json.dumps(payload))
+                print((response.pretty_print()))
+
+        except KeyboardInterrupt:
+            print("PutBLEInfo Stop")
+            client.stop()
+        client.stop()
+
+    def mkJsonbeaconInfo(self, info): # complete
+        n = 2.05
+        distance = math.pow(10, (float(info[4]) - float(info[5])) / (10 * n))
+        payload = {
+            'rpuuid' : self.myuuid,
+            'userMAC' : info[0],
+            'useruuid' : info[1],
+            'distance' : distance,
+            'updateTime' : time.time()
+        }
+        return payload
+
+    def regiRelWithNewPi(self, info): # complete
+        #새로운 rasbPi를 찾은 경우 새로운 rasbPi를 위치측정기로 사용하기 위해서 server에 관련 정보를 저장하는 method
+        path = "/rpGraphInfoPath"
+        
+        path = "coap://" + self.ip + path
+        host, port, path = parse_uri(path)
+        try:
+            tmp = socket.gethostbyname(host)
+            host = tmp
+        except socket.gaierror:
+            pass
+
+        client = HelperClient(server=(host, port))
+
+        try:            
+            response = client.put(path, json.dumps(self.mkJsonRpgraphInfo(info)))
+            print((response.pretty_print()))
+
+        except KeyboardInterrupt:
+            print("obtainMyID Stop")
+            client.stop()
+        client.stop()
+
+    def mkJsonRpgraphInfo(self, info): # complete
+        n = 2.05
+        distance = math.pow(10, ((float(info[4]) - float(info[5])) / (10 * n)))
+        payload = {
+            'v1' : self.myuuid,
+            'v2' : info[1],
+            'distance' : distance
+        }
+        return payload
+
+def main():
+    measuringDevice = CoapClient()
+    measuringDevice.calculateNodePositionAtServer()
+    putBLEInfoThread = threading.Thread(target = measuringDevice.putBLEInfo)
+    putBLEInfoThread.start()
+    putBLEInfoThread.join()
+
+if __name__ == "__main__":
+    main()
diff --git a/Server_CoAP/CoAPthon3/exampleresources.py b/Server_CoAP/CoAPthon3/exampleresources.py
index f568f26..81babc2 100644
--- a/Server_CoAP/CoAPthon3/exampleresources.py
+++ b/Server_CoAP/CoAPthon3/exampleresources.py
@@ -37,17 +37,19 @@ class RpNodeInfoResource(Resource):
         assert(isinstance(response, Response))
         self.payload = json.loads(self.payload)
         if self.payload['option'] == -1:
+            # coapclient.py에서 clearMyData()가 호출된 경우
             self.deleteNodeData(self.payload)
         elif self.payload['option'] == 1:
-            #coapclient.py에서 calculateNodePositionAtServer()이 호출된 경우
+            # coapclient.py에서 calculateNodePositionAtServer()이 호출된 경우
             response.payload = self.calculateNodePosition(self.payload)
         else :
-            # coapclient.py 에서  obtainMyID()가 호출된 경우
+            # coapclient.py에서 obtainMyID()가 호출된 경우
             response.payload = self.postRpNodeInfoInDB(self.payload)
         response.code = defines.Codes.CHANGED.number
         return self, response
 
     def deleteNodeData(self, info): # complete
+        return
         info = info['rpMAC']
         graphColletion = self.db.RpGraphData
         if  self.collection.find({'rpMAC' : info}).count() != 0:
@@ -93,11 +95,11 @@ class RpNodeInfoResource(Resource):
         }
         if mydoc.count() == 1: # 자기 자신이 RpNodeData에 있는 경우
             if self.collection.count() == 1: # 자신이 첫번째 RpNode인 경우
-                self.collection.update({'rpuuid' : info}, {'$set':{'x': 0.0, 'y': 0.0}}, False)
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': 0.0, 'y': 0.0}}, False)
             elif self.collection.count() == 2: # 자신이 두번째 RpNode인 경우
                 graphB = graphColletion.find({'v2': info})
                 x = graphB[0]['distance']
-                self.collection.update({'rpuuid' : info}, {'$set':{'x': x, 'y': 0.0}}, False)
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': 0.0}}, False)
             elif self.collection.count() == 3: # 자신이 세번째 RpNode인 경우
                 graphC = graphColletion.find({'v2': info})
                 for doc in graphC:
@@ -115,20 +117,20 @@ class RpNodeInfoResource(Resource):
                 if ((dis['a'] + dis['b']) <= dis['c']) or dis['a'] == 0 or dis['b'] == 0 or dis['c'] == 0:
                     # 3번째 rpNode를 만들 수 없는 경우
                     print("3번째 rpNode를 만들 수 없습니다.(no triangle)")
-                    response['operate'] = 1
+                    response['operate'] = 0
                     return json.dumps(response)
                 
                 cosA = (math.pow(dis['b'], 2) + math.pow(dis['c'], 2) - math.pow(dis['a'], 2)) / (2 * dis['b'] * dis['c'])
                 if cosA >= 1 or cosA <= -1 :
                     # 3번째 rpNode를 만들 수 없는 경우
                     print("3번째 rpNode를 만들 수 없습니다.(impossible cosA)",cosA) 
-                    response['operate'] = 1
+                    response['operate'] = 0
                     return json.dumps(response)
 
                 sinA = math.sqrt((1 - math.pow(cosA,2)))
                 x = dis['b'] * cosA
                 y = dis['b'] * sinA
-                self.collection.update({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
             else:
                 graphD = graphColletion.find({'v2' : info})
                 nodeLocationData = []
@@ -167,7 +169,7 @@ class RpNodeInfoResource(Resource):
                     response['operate'] = 0
                     return json.dumps(response)
 
-                self.collection.update({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
 
             return json.dumps(response)
         else:
@@ -214,26 +216,27 @@ class RpGraphInfoResource(Resource): # complete
 
     def postRpGraphInfoInDB(self, info): # complete
         info = json.loads(info)
-        mydoc = self.collection.find({'v1':info['v1'], 'v2':info['v2'], 'distance': {'$lte' : 40}})
-        if mydoc.count() > 0:
-            distance = (mydoc[0]['sum']+info['distance']) / (mydoc[0]['count'] + 1)
+        if info['distance'] < 60:
+            mydoc = self.collection.find({'v1':info['v1'], 'v2':info['v2']})
 
-            self.collection.update({ 'v1' : info['v1'], 'v2':info['v2']}, {
-                'v1':info['v1'], 
-                'v2': info['v2'],
-                'distance' : distance,
-                'sum': mydoc[0]['sum']+float(info['distance']),
-                'count': mydoc[0]['count']+1
-                }, upsert=True)
+            if mydoc.count() > 0:
+                distance = (mydoc[0]['sum']+info['distance']) / (mydoc[0]['count'] + 1)
 
-        if mydoc.count() == 0:
-            self.collection.update({ 'v1' : info['v1'], 'v2':info['v2']}, {
-                'v1':info['v1'], 
-                'v2': info['v2'],
-                'distance' : float(info['distance']),
-                'sum': float(info['distance']),
-                'count': 1
-                }, upsert=True)
+                c = mydoc[0]['count'] + 1
+                self.collection.update_one({ 'v1' : info['v1'], 'v2':info['v2']}, {"$set":{
+                    'distance' : distance,
+                    'sum': mydoc[0]['sum']+float(info['distance']),
+                    'count': c
+                    }},upsert = False)
+
+            if mydoc.count() == 0:
+                self.collection.insert_one({
+                    'v1':info['v1'], 
+                    'v2': info['v2'],
+                    'distance' : float(info['distance']),
+                    'sum': float(info['distance']),
+                    'count': 1
+                    })
 
 class BleInfoResource(Resource): # complete
     def __init__(self, name="BleInfo"):
diff --git a/Server_CoAP/CoAPthon3/testresource.py b/Server_CoAP/CoAPthon3/testresource.py
new file mode 100644
index 0000000..015ffcf
--- /dev/null
+++ b/Server_CoAP/CoAPthon3/testresource.py
@@ -0,0 +1,281 @@
+import json
+import uuid
+import math
+import triangulation
+from pymongo import MongoClient
+from coapthon import defines
+from coapthon.resources.resource import Resource
+
+class RpNodeInfoResource(Resource):
+    def __init__(self, name="RpNodeInfo"):
+        super(RpNodeInfoResource, self).__init__(name)
+        self.payload = "RpNodeInfo resource"
+        try:
+            self.conn = MongoClient('mongodb://iotuser:iotsystem@localhost/IoT_System', 27017)
+            self.db = self.conn.IoT_System
+            self.collection = self.db.testNode
+        except:
+            print("Could not connect to MongoDB")
+
+    def render_POST_advanced(self, request, response):
+        self.payload = request.payload
+        from coapthon.messages.response import Response
+        assert(isinstance(response, Response))
+        self.payload = json.loads(self.payload)
+        if self.payload['option'] == -1:
+            self.deleteNodeData(self.payload)
+        elif self.payload['option'] == 1:
+            response.payload = self.calculateNodePosition(self.payload)
+        else : 
+            response.payload = self.postRpNodeInfoInDB(self.payload)
+        response.code = defines.Codes.CREATED.number
+        return self, response
+
+    def render_PUT_advanced(self, request, response):
+        self.payload = request.payload
+        from coapthon.messages.response import Response
+        assert(isinstance(response, Response))
+        self.payload = json.loads(self.payload)
+        if self.payload['option'] == -1:
+            # coapclient.py에서 clearMyData()가 호출된 경우
+            self.deleteNodeData(self.payload)
+        elif self.payload['option'] == 1:
+            # coapclient.py에서 calculateNodePositionAtServer()이 호출된 경우
+            response.payload = self.calculateNodePosition(self.payload)
+        else :
+            # coapclient.py에서 obtainMyID()가 호출된 경우
+            response.payload = self.postRpNodeInfoInDB(self.payload)
+        response.code = defines.Codes.CHANGED.number
+        return self, response
+
+    def deleteNodeData(self, info): # complete
+        info = info['rpMAC']
+        graphColletion = self.db.testGraph
+        if  self.collection.find({'rpMAC' : info}).count() != 0:
+            rpuuid = self.collection.find({'rpMAC' : info})[0]['rpuuid']
+            graphColletion.remove({'v2' : rpuuid})
+            self.collection.remove({'rpMAC' : info})
+
+    def postRpNodeInfoInDB(self, info): # complete
+        info = info['rpMAC']
+        rpuuid = "52528282"+str(uuid.uuid4())[8:]
+        rpuuid = rpuuid.replace("-","")
+        if self.collection.count() == 0: # 첫번째 rpNode인 경우
+            payload = {
+                'rpMAC' : info,
+                'rpuuid' : rpuuid
+            }
+            self.collection.insert_one(payload)
+
+            response = json.dumps({
+                'rpuuid' : rpuuid,
+                'operate' : 0 # advertise할 필요가 없다.
+            })
+        else:
+            payload = {
+                'rpMAC' : info,
+                'rpuuid' : rpuuid
+            }
+            self.collection.insert_one(payload)
+
+            response = json.dumps({
+                'rpuuid' : rpuuid,
+                'operate' : 1 # advertise를 해야한다.
+            })
+        return response
+
+    def calculateNodePosition(self, info): # complete , need to check 4-th case.
+        print("Start calculateNodePosition")
+        info = info['rpuuid']
+        graphColletion = self.db.testGraph
+        mydoc = self.collection.find({'rpuuid': info})
+        response = {
+            'operate' : 1
+        }
+        if mydoc.count() == 1: # 자기 자신이 RpNodeData에 있는 경우
+            if self.collection.count() == 1: # 자신이 첫번째 RpNode인 경우
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': 0.0, 'y': 0.0}}, False)
+            elif self.collection.count() == 2: # 자신이 두번째 RpNode인 경우
+                graphB = graphColletion.find({'v2': info})
+                x = graphB[0]['distance']
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': 0.0}}, False)
+            elif self.collection.count() == 3: # 자신이 세번째 RpNode인 경우
+                graphC = graphColletion.find({'v2': info})
+                for doc in graphC:
+                    tempdoc = self.collection.find({'rpuuid': doc['v1']})
+                    if tempdoc[0]['x'] == 0 and tempdoc[0]['y'] == 0: # 첫번째 RpNode 즉, (0,0)
+                        vertexA = tempdoc[0]# 첫번째 RpNode를 vertexA라 한다.
+                    elif tempdoc[0]['y'] == 0:    
+                        vertexB = tempdoc[0]#두번째 RpNode를 vertexB라  한다.
+
+                dis = {
+                    'a': graphColletion.find({'v1': vertexB['rpuuid'], 'v2': info})[0]['distance'],
+                    'b': graphColletion.find({'v1': vertexA['rpuuid'], 'v2': info})[0]['distance'],
+                    'c': vertexB['x']
+                }
+                if ((dis['a'] + dis['b']) <= dis['c']) or dis['a'] == 0 or dis['b'] == 0 or dis['c'] == 0:
+                    # 3번째 rpNode를 만들 수 없는 경우
+                    print("3번째 rpNode를 만들 수 없습니다.(no triangle)")
+                    response['operate'] = 0
+                    return json.dumps(response)
+                
+                cosA = (math.pow(dis['b'], 2) + math.pow(dis['c'], 2) - math.pow(dis['a'], 2)) / (2 * dis['b'] * dis['c'])
+                if cosA >= 1 or cosA <= -1 :
+                    # 3번째 rpNode를 만들 수 없는 경우
+                    print("3번째 rpNode를 만들 수 없습니다.(impossible cosA)",cosA) 
+                    response['operate'] = 0
+                    return json.dumps(response)
+
+                sinA = math.sqrt((1 - math.pow(cosA,2)))
+                x = dis['b'] * cosA
+                y = dis['b'] * sinA
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
+            else:
+                graphD = graphColletion.find({'v2' : info})
+                nodeLocationData = []
+
+                for g in graphD:
+                    nodeLocationData.append({
+                    'rpuuid': g['v1'],
+                    'distance': g['distance']
+                })
+
+                nodeLocationData = sorted(nodeLocationData, key=lambda k: k['distance'], reverse = False)
+
+                if len(nodeLocationData) < 3:
+                    # 4번째 이상의 rpNode를 만들 수 없는 경우
+                    print("4번째 이상의 rpNode를 만들 수 없습니다.")
+                    response['operate'] = 0
+                    return json.dumps(response)
+
+                nodeList = []
+               
+                for i in range(3):
+                    print(self.collection.find({'rpuuid': nodeLocationData[i]['rpuuid']})[0])
+                    nodeList.append({
+                        'x': self.collection.find({'rpuuid': nodeLocationData[i]['rpuuid']})[0]['x'],
+                        'y': self.collection.find({'rpuuid': nodeLocationData[i]['rpuuid']})[0]['y'],
+                        'distance': nodeLocationData[i]['distance']
+                    })
+
+                triangulationInst = triangulation.Triangulation(nodeList[:3])
+                print("test : ", nodeList[:3])
+                x, y = triangulationInst.doTriangulation()
+                print("x: ",x,"y : ",y)
+                if x == None:
+                    # 4번째 이상의 rpNode를 만들 수 없는 경우
+                    print("4번째 이상의 rpNode를 만들 수 없습니다.")
+                    response['operate'] = 0
+                    return json.dumps(response)
+
+                self.collection.update_one({'rpuuid' : info}, {'$set':{'x': x, 'y': y}}, False)
+
+            return json.dumps(response)
+        else:
+            response['operate'] = 0
+            return json.dumps(response)
+                
+class RpGraphInfoResource(Resource): # complete
+    def __init__(self, name="RpGraphInfo"):
+        super(RpGraphInfoResource, self).__init__(name)
+        self.payload = "RpGraphInfo resource"
+        try:
+            self.conn = MongoClient('mongodb://iotuser:iotsystem@localhost/IoT_System', 27017)
+        except:
+            print("Could not connect to MongoDB")
+        self.db = self.conn.IoT_System
+        self.collection = self.db.testGraph
+        
+    def render_GET_advanced(self, request, response):
+        response.payload = self.payload
+        response.max_age = 20
+        response.code = defines.Codes.CONTENT.number
+        return self, response
+
+    def render_POST_advanced(self, request, response):
+        self.payload = request.payload
+        from coapthon.messages.response import Response
+        assert(isinstance(response, Response))
+        response.payload = self.postRpGraphInfoInDB(self.payload)
+        response.code = defines.Codes.CREATED.number
+        return self, response
+
+    def render_PUT_advanced(self, request, response):
+        self.payload = request.payload
+        from coapthon.messages.response import Response
+        assert(isinstance(response, Response))
+        response.payload = self.postRpGraphInfoInDB(self.payload)
+        response.code = defines.Codes.CHANGED.number
+        return self, response
+
+    def render_DELETE_advanced(self, request, response):
+        response.payload = "Response deleted"
+        response.code = defines.Codes.DELETED.number
+        return True, response
+
+    def postRpGraphInfoInDB(self, info): # complete
+        info = json.loads(info)
+        if info['distance'] < 60:
+            mydoc = self.collection.find({'v1':info['v1'], 'v2':info['v2']})
+
+            if mydoc.count() > 0:
+                distance = (mydoc[0]['sum']+info['distance']) / (mydoc[0]['count'] + 1)
+
+                c = mydoc[0]['count'] + 1
+                self.collection.update_one({ 'v1' : info['v1'], 'v2':info['v2']}, {"$set":{
+                    'distance' : distance,
+                    'sum': mydoc[0]['sum']+float(info['distance']),
+                    'count': c
+                    }},upsert = False)
+
+            if mydoc.count() == 0:
+                self.collection.insert_one({
+                    'v1':info['v1'], 
+                    'v2': info['v2'],
+                    'distance' : float(info['distance']),
+                    'sum': float(info['distance']),
+                    'count': 1
+                    })
+
+class BleInfoResource(Resource): # complete
+    def __init__(self, name="BleInfo"):
+        super(BleInfoResource, self).__init__(name)
+        self.payload = "BleInfo resource"
+        try:
+            self.conn = MongoClient('mongodb://iotuser:iotsystem@localhost/IoT_System', 27017)
+            self.db = self.conn.IoT_System
+            self.collection = self.db.testTracking
+        except:
+            print("Could not connect to MongoDB")
+
+    def render_GET_advanced(self, request, response):
+        response.payload = self.payload
+        response.max_age = 20
+        response.code = defines.Codes.CONTENT.number
+        return self, response
+
+    def render_POST_advanced(self, request, response):
+        self.payload = request.payload
+        self.postBLEInfoInDB(self.payload)
+        from coapthon.messages.response import Response
+        assert isinstance(response, Response)
+        response.payload = "Response changed through POST"
+        response.code = defines.Codes.CREATED.number
+        return self, response
+
+    def render_PUT_advanced(self, request, response):
+        self.payload = request.payload
+        self.postBLEInfoInDB(self.payload)
+        from coapthon.messages.response import Response
+        assert isinstance(response, Response)
+        response.payload = "Response changed through PUT"
+        response.code = defines.Codes.CHANGED.number
+        return self, response
+
+    def render_DELETE_advanced(self, request, response):
+        response.payload = "Response deleted"
+        response.code = defines.Codes.DELETED.number
+        return True, response
+
+    def postBLEInfoInDB(self, payload):
+        self.collection.insert_many(json.loads(payload))
\ No newline at end of file
diff --git a/Server_CoAP/CoAPthon3/testserver.py b/Server_CoAP/CoAPthon3/testserver.py
new file mode 100644
index 0000000..c56150d
--- /dev/null
+++ b/Server_CoAP/CoAPthon3/testserver.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+import getopt
+import sys
+import threading
+import _thread
+import time
+import datetime
+import json
+import triangulation
+from coapthon.server.coap import CoAP
+from testresource import BleInfoResource, RpNodeInfoResource, RpGraphInfoResource
+from pymongo import MongoClient
+
+class CoAPServer(CoAP):
+    def __init__(self, host, port, multicast=False): # complete
+        CoAP.__init__(self, (host, port), multicast)
+        self.add_resource('bleInfoPath/', BleInfoResource())
+        self.add_resource('rpNodeInfoPath/', RpNodeInfoResource())
+        self.add_resource('rpGraphInfoPath/', RpGraphInfoResource())
+
+        print(("CoAP Server start on " + host + ":" + str(port)))
+        print((self.root.dump()))
+
+        try:
+            self.conn = MongoClient('mongodb://iotuser:iotsystem@localhost/IoT_System', 27017)
+            self.db = self.conn.IoT_System
+            self.piNodeCollection = self.db.RpNodeData
+            self.userNodeCollection = self.db.UserNodeData
+            self.trackingCollection = self.db.TrackingData
+            self.usersCollection = self.db.users
+            self.updatePeriod = 10
+            self.limitDistance = 40
+        except:
+            print("Could not connect to MongoDB")
+
+    def updateUserLocation(self): # complete
+        try:
+            while True:
+                cursor = self.usersCollection.find()
+                for c in cursor:
+                    positionCalculationThread = threading.Thread(target = self.positionCalculation, args=([c['uuid']]))
+                    positionCalculationThread.start()
+                time.sleep(self.updatePeriod)
+                #trackingCursor = self.trackingCollection.remove({'updateTime': {'$lte' : currentTime - self.updatePeriod}})
+        except KeyboardInterrupt:
+            print("existing updateUserLocation")
+    
+    def positionCalculation(self, useruuid): # complete but need to check triangulation.py
+        print(useruuid)
+        currentTime = time.time()
+        trackingCursor = self.trackingCollection.find({'$and':[{'useruuid': useruuid},
+        {'updateTime':{'$gt' : currentTime - self.updatePeriod}},{'distance': {'$lt' : self.limitDistance}}]})
+        #trackingCursor = self.trackingCollection.find({'$and':[{'useruuid':{'$eq' : useruuid}}]})
+        userLocationData =[]
+
+        flag = 0
+        for c in trackingCursor:
+            for i in userLocationData:
+                if i['rpuuid'] == c['rpuuid']:
+                    i['sum']+= c['distance']
+                    i['count']+=1
+                    i['distance'] = i['sum']/i['count']
+                    flag = 1
+                    break
+            if flag == 0:
+                userLocationData.append({
+                    'rpuuid': c['rpuuid'],
+                    'distance': c['distance'],
+                    'sum': c['distance'],
+                    'count':1
+                })
+            flag = 0
+
+        userLocationData = sorted(userLocationData, key=lambda k: k['distance'], reverse = False)
+        for u in userLocationData:
+            print(userLocationData)
+        
+        if len(userLocationData) == 0:
+            print("userLocationData == 0")
+            return
+        
+        rp1uuid = userLocationData[0]['rpuuid']
+        rp1 = self.piNodeCollection.find({'rpuuid' : rp1uuid})
+
+        if len(userLocationData) < 3:
+            print("userLocationData < 3")
+            dd = datetime.datetime.utcnow()
+            userNodeData = {
+                'rp1': {'rpuuid' : userLocationData[0]['rpuuid'], 'distance': userLocationData[0]['distance']},
+                'useruuid': useruuid,
+                'x' : rp1[0]['x'],
+                'y' : rp1[0]['y'],
+                'updateTime': str(dd)
+            }
+            print(userNodeData)
+            self.userNodeCollection.insert_one(userNodeData)
+            return
+
+        else :
+            nodeList = []
+            for i in range(3):
+                nodeList.append({
+                    'x': self.piNodeCollection.find({'rpuuid': userLocationData[i]['rpuuid']})[0]['x'],
+                    'y': self.piNodeCollection.find({'rpuuid': userLocationData[i]['rpuuid']})[0]['y'],
+                    'distance': userLocationData[i]['distance']
+                })
+
+            triangulationInst = triangulation.Triangulation(nodeList[:3])
+            x, y = triangulationInst.doTriangulation()
+
+            if x == None:
+                print("no solution")
+                dd = datetime.datetime.utcnow()
+                userNodeData = {
+                    'rp1': {'rpuuid' : userLocationData[0]['rpuuid'], 'distance': userLocationData[0]['distance']},
+                    'useruuid': useruuid,
+                    'x': rp1[0]['x'],
+                    'y': rp1[0]['y'],
+                    'updateTime': str(dd)
+                }
+                print(userNodeData)
+                self.userNodeCollection.insert_one(userNodeData)
+                return
+
+            dd = datetime.datetime.utcnow()
+            userNodeData = {
+                'rp1': {'rpuuid' : userLocationData[0]['rpuuid'], 'distance': userLocationData[0]['distance']},
+                'rp2': {'rpuuid' : userLocationData[1]['rpuuid'], 'distance' : userLocationData[1]['distance']},
+                'rp3': {'rpuuid' : userLocationData[2]['rpuuid'], 'distance' : userLocationData[2]['distance']},
+                'useruuid': useruuid,
+                'x': x,
+                'y': y,
+                'updateTime': str(dd)
+            }
+            print(userNodeData)
+        self.userNodeCollection.insert_one(userNodeData)
+
+def usage():  # pragma: no cover
+    print("coapserver.py -i <ip address> -p <port>")
+
+
+def main(argv):  # pragma: no cover
+    ip = "0.0.0.0"
+    port = 5683
+    multicast = False
+    try:
+        opts, args = getopt.getopt(argv, "hi:p:m", ["ip=", "port=", "multicast"])
+    except getopt.GetoptError:
+        usage()
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt == '-h':
+            usage()
+            sys.exit()
+        elif opt in ("-i", "--ip"):
+            ip = arg
+        elif opt in ("-p", "--port"):
+            port = int(arg)
+        elif opt in ("-m", "--multicast"):
+            multicast = True
+
+    server = CoAPServer(ip, port, multicast)
+    try:
+        #updateUserLocationThread = threading.Thread(target = server.updateUserLocation)
+        #updateUserLocationThread.start()
+        server.listen(10)
+
+    except KeyboardInterrupt:
+        print("Server Shutdown")
+        server.close()
+        print("Exiting...")
+
+
+if __name__ == "__main__":  # pragma: no cover
+    main(sys.argv[1:])
diff --git a/Server_Vue_Express/backend/routes/api.js b/Server_Vue_Express/backend/routes/api.js
index d7832e8..18e1ede 100644
--- a/Server_Vue_Express/backend/routes/api.js
+++ b/Server_Vue_Express/backend/routes/api.js
@@ -166,7 +166,7 @@ router.get('/rpis/:id', function(req, res, next) {
                 '$gt': lastUpdateTime - 60,
                 
               },
-              distance: {'$lt': 40}
+              distance: {'$lt': 50}
             }
           }, {
             '$group': {
@@ -175,7 +175,9 @@ router.get('/rpis/:id', function(req, res, next) {
           }
         ]);
         await rpNode.find({'rpuuid': ra[i]._id},(err,output)=>{
-          if(output[0].rpname.indexOf(req.params.id) != -1 || req.params.id == "*")
+          if(output.length == 0)
+            ;
+          else if(output[0].rpname.indexOf(req.params.id) != -1 || req.params.id == "*")
             data.push({
               rpuuid: ra[i]._id,
               rpname: output[0].rpname,
@@ -183,7 +185,9 @@ router.get('/rpis/:id', function(req, res, next) {
             });
         });
       }
-      res.render('rpis',{data});
+      const searchValue = req.params.id == '*'?"":req.params.id ;
+       
+      res.render('rpis',{data, searchValue});
     })();
 
   });
@@ -220,7 +224,7 @@ router.get('/aggregateByRPUUID/:id', function(req, res, next) {
                   '$gt': lastUpdateTime - 60*i - 60,
                   
                 },
-                distance: {'$lt': 40}
+                distance: {'$lt': 50}
               }
             }, {
               '$group': {
diff --git a/Server_Vue_Express/backend/views/rpis.pug b/Server_Vue_Express/backend/views/rpis.pug
index 7ea09a1..c106fa8 100644
--- a/Server_Vue_Express/backend/views/rpis.pug
+++ b/Server_Vue_Express/backend/views/rpis.pug
@@ -1,8 +1,8 @@
 extends layout
 
 block content
-  input(type='text' id='input' name='rpiSearch' placeholder='검색할 단어를 입력하세요')
-  button(onclick='const k =document.getElementById("input").value; location.href=  k!= ""?k:"*" ') 검색
+  input(type='text' id='input' name='rpiSearch' placeholder='검색할 단어를 입력하세요' value=searchValue)
+  button(onclick='const k =document.getElementById("input").value; location.href=  k!= ""?k:"*" ' ) 검색
   hr(size='3px')
   p
     - let i=0;
-- 
GitLab