Arduino (1) traffic_light.ino ``` #include <TrafficLight.h> #include <LiquidCrystal_I2C.h> #include <Wire.h> #include <ArduinoJson.h> #include <Timer.h> // Module connection pins (Digital Pins) #define DIO1 22 #define CLK1 23 #define DIO2 26 #define CLK2 27 #define DIO3 24 #define CLK3 25 #define DIO4 28 #define CLK4 29 //declare 4 traffic lights TrafficLight light_a(1, 90, CLK1, DIO1); // TrafficLight(dir, deafult sec, CLK, DIO) TrafficLight light_b(1, 90, CLK2, DIO2); TrafficLight light_c(2, 90, CLK3, DIO3); TrafficLight light_d(2, 90, CLK4, DIO4); int operand; float second; int nowDirect; // 1->ab; 2->cd; int lastUpdate; const long interval = 1000; String received; String message; boolean NODEMCU_DISCONNECT = 1; Timer sendESP; StaticJsonDocument<1024> data; StaticJsonDocument<1024> esp_data; LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 設定 LCD I2C 位址 void setup() { //初始化序列埠 initSerial(); //初始化 lcd initLCD(); // 等待 nodemcu waitNodeMCU(); //等待 arduino led controller waitLightController(); //設定初始秒數 (皆為 a 的初始秒數) //設定初始紅燈方向為 1<--->2 (1) // (direct, second) setDirAndSec(1, light_a.defaultSec + 1); //每 3 秒傳送秒數資料給 NodeMCU sendESP.every(2000, sendJSON); } void loop() { //秒數扣1 minus(); //判斷是否需要切換方向 checkSwitch(); //顯示秒數 (紅燈方向才顯示) showSecond(); //把當前秒數, 當前方向 放到 data 字典檔裡面 data["now_second"] = light_a.nowSec; data["now_direct"] = nowDirect; // 傳送資料到 NodeMCU sendESP.update(); // 監聽 NodeMCU 的訊息 (秒數變動) listenToNodeMCU(); //延遲一秒 delay(1000); } void initSerial() { Serial.begin(9600); //usb slot Serial1.begin(9600); //for TX/RX message on arduino 2 (light controller) Serial2.begin(9600); // for Transmit seconds to NodeMCU(TX only) Serial3.begin(9600); //for Receive data from NodeMCU(RX only) Serial.println("hi"); } void initLCD() { lcd.begin(16, 2); // 初始化 LCD,一行 16 的字元,共 2 行,預設開啟背光 lcd.clear(); } void waitNodeMCU() { lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("Waiting for"); lcd.setCursor(0, 1); // 設定游標位置在第二行行首 lcd.print("NodeMCU WIFI.."); delay(1000); //busy wait.. while (NODEMCU_DISCONNECT) { if (Serial3.available() > 0) { if (Serial3.read() == 100) { NODEMCU_DISCONNECT = 0; } } } //Connected! lcd.clear(); lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("WIFI Connected!"); delay(1000); } void waitLightController() { // 等待 Light Controller lcd.setCursor(0, 0); lcd.print("Waiting for"); lcd.setCursor(0, 1); lcd.print("Light Controller"); delay(1000); //busy wait.. while (Serial1.available() == 0) {} lcd.clear(); lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("Connected!"); delay(1000); //lcd 顯示號誌初始狀態 lcd.clear(); lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("Red: 1-2"); lcd.setCursor(0, 1); // 設定游標位置在第一行行首 lcd.print("Status: Normal"); } void setDirAndSec(int direct, int sec) { //告知切換方向 nowDirect = direct; Serial1.print(nowDirect); //設定秒數 light_a.init(sec); light_b.init(sec); light_c.init(sec); light_d.init(sec); } void sendJSON() { serializeJsonPretty(data, Serial2); if (nowDirect == 1) { Serial1.print(nowDirect); } else if (nowDirect == 2) { Serial1.print(nowDirect); } lcd.setCursor(0, 1); // 設定游標位置在第一行行首 lcd.print("Status: Normal "); } void minus() { //秒數扣1 light_a.minus(1); light_b.minus(1); light_c.minus(1); light_d.minus(1); } void checkSwitch() { //當秒數為 0 時, 變更方向 if (light_a.nowSec <= 0 || light_c.nowSec <= 0) { lcd.setCursor(0, 1); // 設定游標位置在第一行行首 //如果 1 <---> 2 方向是紅燈 if (nowDirect == 1) { //變更方向為 3 <----> 4 nowDirect = 2; Serial1.print(nowDirect); light_a.setSec(light_c.variaSec); light_b.setSec(light_c.variaSec); light_c.setSec(light_c.variaSec); light_d.setSec(light_c.variaSec); lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("Red: 3-4"); } else { //如果 3 <---> 4 方向是紅燈 //變更方向為 1 <----> 2 nowDirect = 1; Serial1.print(nowDirect); light_a.setSec(light_a.variaSec); light_b.setSec(light_a.variaSec); light_c.setSec(light_a.variaSec); light_d.setSec(light_a.variaSec); lcd.setCursor(0, 0); // 設定游標位置在第一行行首 lcd.print("Red: 1-2"); } } } void showSecond() { if (nowDirect == 1) { light_a.show(); light_b.show(); light_c.clear(); light_d.clear(); } else if (nowDirect == 2) { light_c.show(); light_d.show(); light_a.clear(); light_b.clear(); } } void listenToNodeMCU() { if (Serial3.available() > 0) { //讀取訊息 received = Serial3.readString(); //訊息剖析 (Deserialize) DeserializationError error = deserializeJson(esp_data, received); if (error) { switch (error.code()) { case DeserializationError::Ok: Serial.print(F("Deserialization succeeded")); break; case DeserializationError::InvalidInput: Serial.print(F("Invalid input!")); break; case DeserializationError::NoMemory: Serial.print(F("Not enough memory")); break; default: Serial.print(F("Deserialization failed")); break; } } else { //訊息萃取 (To integer) second = esp_data["second"]; operand = esp_data["operand"]; //調整秒數 (switch case) adjustSecond(second, operand); //lcd print message lcd.setCursor(0, 1); lcd.print(message); } } } void adjustSecond(float sec, int oper) { //調整秒數 1->"+"; 2->"-"; 3->"*"; 4->"/"; 5->"=" Serial.print("adjust second:"); Serial.println(sec); Serial.print("operand:"); Serial.print(oper); switch (oper) { case 1: //"+" message = "Add "; light_a.add(int(sec)); light_b.add(int(sec)); light_c.add(int(sec)); light_d.add(int(sec)); break; case 2: //"-" message = "Minus "; if ((light_c.nowSec - sec ) <= 0) { light_a.nowSec = 0; light_b.nowSec = 0; light_c.nowSec = 0; light_d.nowSec = 0; } else { light_a.minus(int(sec)); light_b.minus(int(sec)); light_c.minus(int(sec)); light_d.minus(int(sec)); } break; case 3: //"*" message = "Mutiply "; light_a.multiply(sec); light_b.multiply(sec); light_c.multiply(sec); light_d.multiply(sec); break; case 4: //"/" message = "Divide "; light_a.divide(sec); light_b.divide(sec); light_c.divide(sec); light_d.divide(sec); break; case 5: //"=" message = "Divide "; light_a.setSec(int(sec)); light_b.setSec(int(sec)); light_c.setSec(int(sec)); light_d.setSec(int(sec)); break; } } ``` (2)control_led ``` #define RED1 22 #define GREEN1 23 #define RED2 26 #define GREEN2 27 #define RED3 24 #define GREEN3 25 #define RED4 28 #define GREEN4 29 String DIR1 = "49"; //ASCII -> 1 String DIR2 = "50"; //ASCII -> 2 String received; void setup() { initSerial(); initLight(); Serial1.write(100); //transmit init message to main controller } void loop() { //listen to main controller listenToMainController(); } void initSerial() { Serial.begin(9600); Serial1.begin(9600); } void initLight() { pinMode(RED1, OUTPUT); pinMode(GREEN1, OUTPUT); pinMode(RED2, OUTPUT); pinMode(GREEN2, OUTPUT); pinMode(RED3, OUTPUT); pinMode(GREEN3, OUTPUT); pinMode(RED4, OUTPUT); pinMode(GREEN4, OUTPUT); digitalWrite(RED1, HIGH); digitalWrite(GREEN1, LOW); digitalWrite(RED2, HIGH); digitalWrite(GREEN2, LOW); digitalWrite(RED3, LOW); digitalWrite(GREEN3, HIGH); digitalWrite(RED4, LOW); digitalWrite(GREEN4, HIGH); } void listenToMainController() { if (Serial1.available() > 0) { received = Serial1.read(); Serial.println(received); if (received == DIR1) { digitalWrite(RED1, HIGH); digitalWrite(GREEN1, LOW); digitalWrite(RED2, HIGH); digitalWrite(GREEN2, LOW); digitalWrite(RED3, LOW); digitalWrite(GREEN3, HIGH); digitalWrite(RED4, LOW); digitalWrite(GREEN4, HIGH); } else if (received == DIR2) { digitalWrite(RED1, LOW); digitalWrite(GREEN1, HIGH); digitalWrite(RED2, LOW); digitalWrite(GREEN2, HIGH); digitalWrite(RED3, HIGH); digitalWrite(GREEN3, LOW); digitalWrite(RED4, HIGH); digitalWrite(GREEN4, LOW); } } } ``` NodeMCU ``` #include <ArduinoJson.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <ESP8266WebServer.h> const char* ssid = "ASUS_Aaron_2G"; const char* password = "0981429828"; WiFiServer wifiServer(2345); ESP8266WebServer server(80); HTTPClient http; StaticJsonDocument<200> doc; StaticJsonDocument<200> doc1; JsonObject data = doc1.to<JsonObject>(); String received = ""; String url = ""; String page, page2, page3; int now; int past; int httpCode; int value; int sending; String second, operand; long now_direct, now_second; void setup() { initSerial(); //waiting for wifi connection initWIFI(); //start wifi server initWIFIServer(); //send init message to main controller Serial1.write(100); } void loop() { listenToMainController(); server.handleClient(); } void listenToMainController() { while (Serial.available() > 0) { received = Serial.readString(); Serial.println(received); DeserializationError error = deserializeJson(doc, received); JsonObject data = doc.as<JsonObject>(); now_second = data["now_second"]; now_direct = data["now_direct"]; passInfo(now_direct, now_second); } } void initSerial() { Serial.begin(9600); // for receiving seconds from Arduino Serial1.begin(9600);// for transmitting operator and operands //D4 } void initWIFI() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.println("Connecting..."); delay(1000); } Serial.print("Conntected to Wifi. IP:"); Serial.println(WiFi.localIP()); wifiServer.begin(); Serial.println("port 2345 opened"); Serial.println(WiFi.macAddress()); } void initWIFIServer() { //page info page = "<h1>NodeMCU Web Server</h1>"; server.on("/", []() { server.send(200, "text/html", page); }); server.on("/change", []() { operand = server.arg(0); second = server.arg(1); page2 = "<h1>Operand:" + operand; page2 += "</h1><h1><p>Data:"; page2 += second; page2 += "</p></h1>"; server.send(200, "text/html", page2); data["operand"] = operand; data["second"] = second; Serial.print("operand:"); Serial.print(operand); Serial.println("second:"); Serial.print(second); //send message to Arduino serializeJsonPretty(data, Serial1); }); server.begin(); } void passInfo(int dir, int sec) { url = "http://192.168.50.46/arduino/" + String(dir) + "/" + String(sec); http.begin(url); httpCode = http.GET(); http.end(); } ``` Custom Library (1)TrafficLight.h ``` #define TrafficLight_h #include "TM1637Display.h" class TrafficLight { public: TrafficLight(int dir, int sec, int CLK, int DIO); void init(int sec); void show(); void add(int sec); void minus(int sec); void multiply(float sec); void divide(float sec); void setSec(int sec); void changeVariaSec(int sec); void clear(); int direction; int defaultSec; int nowSec; int variaSec; TM1637Display TM1637; }; ``` (2)TrafficLight.cpp ``` #include "TrafficLight.h" TrafficLight::TrafficLight(int dir, int sec, int CLK, int DIO):TM1637(CLK, DIO) { direction = dir; defaultSec = sec; variaSec = sec; } void TrafficLight::init(int sec){ TM1637.setBrightness(0x0f); nowSec = sec; TM1637.showNumberDec(sec); } void TrafficLight::show(){ TM1637.showNumberDec(nowSec); } void TrafficLight::setSec(int sec){ nowSec = sec; } void TrafficLight::add(int sec){ nowSec += sec; } void TrafficLight::minus(int sec){ nowSec -= sec; } void TrafficLight::multiply(float sec){ float temp = nowSec * sec; nowSec = int(temp); } void TrafficLight::divide(float sec){ float temp = nowSec / sec; nowSec = int(temp); } void TrafficLight::changeVariaSec(int sec){ variaSec -= sec; } void TrafficLight::clear(){ TM1637.clear(); } ``` Raspberry Pi Camera Server (1)app.py ``` #!/usr/bin/env python from importlib import import_module import os from flask import Flask, render_template, Response, request from camera_opencv import Camera app = Flask(__name__) def gen2(camera): """Returns a single image frame""" frame = camera.get_frame() yield frame @app.route('/image') def image(): """Returns a single current image for the webcam""" cameraID = request.args.get('cid') return Response(gen2(Camera()), mimetype='image/jpeg') def gen(camera): while True: frame = camera.get_frame() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/stream') def stream(): cameraID = request.args.get('cid') #return Response(gen(VideoCamera(cameraID)), mimetype='multipart/x-mixed-replace; boundary=frame') return Response(gen(Camera()), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0', port='5000', threaded=True) ``` (2)base_camera.py ``` import time import threading try: from greenlet import getcurrent as get_ident except ImportError: try: from thread import get_ident except ImportError: from _thread import get_ident class CameraEvent(object): """An Event-like class that signals all active clients when a new frame is available. """ def __init__(self): self.events = {} def wait(self): """Invoked from each client's thread to wait for the next frame.""" ident = get_ident() if ident not in self.events: # this is a new client # add an entry for it in the self.events dict # each entry has two elements, a threading.Event() and a timestamp self.events[ident] = [threading.Event(), time.time()] return self.events[ident][0].wait() def set(self): """Invoked by the camera thread when a new frame is available.""" now = time.time() remove = None for ident, event in self.events.items(): if not event[0].isSet(): # if this client's event is not set, then set it # also update the last set timestamp to now event[0].set() event[1] = now else: # if the client's event is already set, it means the client # did not process a previous frame # if the event stays set for more than 5 seconds, then assume # the client is gone and remove it if now - event[1] > 5: remove = ident if remove: del self.events[remove] def clear(self): """Invoked from each client's thread after a frame was processed.""" self.events[get_ident()][0].clear() class BaseCamera(object): thread = None # background thread that reads frames from camera frame = None # current frame is stored here by background thread last_access = 0 # time of last client access to the camera event = CameraEvent() def __init__(self): """Start the background camera thread if it isn't running yet.""" if BaseCamera.thread is None: BaseCamera.last_access = time.time() # start background frame thread BaseCamera.thread = threading.Thread(target=self._thread) BaseCamera.thread.start() # wait until frames are available while self.get_frame() is None: time.sleep(0) def get_frame(self): """Return the current camera frame.""" BaseCamera.last_access = time.time() # wait for a signal from the camera thread BaseCamera.event.wait() BaseCamera.event.clear() return BaseCamera.frame @staticmethod def frames(): """"Generator that returns frames from the camera.""" raise RuntimeError('Must be implemented by subclasses.') @classmethod def _thread(cls): """Camera background thread.""" print('Starting camera thread.') frames_iterator = cls.frames() for frame in frames_iterator: BaseCamera.frame = frame BaseCamera.event.set() # send signal to clients time.sleep(0) # if there hasn't been any clients asking for frames in # the last 10 seconds then stop the thread if time.time() - BaseCamera.last_access > 10: try: frames_iterator.close() print('Stopping camera thread due to inactivity.') except GeneratorExit: print("Generator Exit error") finally: print("finally") break BaseCamera.thread = None ``` (3)camera_opencv.py ``` import cv2 from base_camera import BaseCamera class Camera(BaseCamera): video_source = 0 @staticmethod def set_video_source(source): Camera.video_source = source @staticmethod def frames(): camera = cv2.VideoCapture(Camera.video_source) camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) if not camera.isOpened(): raise RuntimeError('Could not start camera.') while True: # read current frame _, img = camera.read() # encode as a jpeg image and return it try: yield cv2.imencode('.jpg', img)[1].tobytes() except GeneratorExit: print("image encode error") ``` Python Task Server ``` # -*- coding: utf-8 -*- """ Created on Tue Jan 29 13:29:40 2019 @author: chaos """ from darkflow.net.build import TFNet import cv2 from io import BytesIO import time import requests from PIL import Image, ImageDraw, ImageFont import numpy as np from time import gmtime, strftime import threading import queue import pygame import boto3 import json import webbrowser #darkflow options = {"model": "cfg/yolo.cfg", "load": "bin/yolov2.weights", "threshold": 0.05} tfnet = TFNet(options) #line notify _token = 'yourToken' #管理單位 token = 'yourAnotherToken' #維修單位 #laravel API maintenance_url = 'http://127.0.0.1/api/maintenance/generate' #sns arnID='yourARNID' count_dict = {"cam1":0, "cam2":0, "cam3":0, "cam4":0} error_count_dict = {"cam1":0, "cam2":0, "cam3":0, "cam4":0} #功能開關(default=False) OPEN_NOTIFY = False OPEN_RULE = False #排程時間 timegap = 2 #記錄 物件辨識最後一次的執行時間 lastUpdated = int(round(time.time())) #pygame 基本設定 pygame.init() pygame.font.init() screen = pygame.display.set_mode((1280, 870)) image = pygame.image.load('cars/error.jpg') icon = pygame.image.load('images/icon.png') waiting = pygame.image.load("images/waiting.png") waiting = pygame.transform.scale(waiting, (400, 400)) warning = pygame.image.load("images/warning.png") pygame.display.set_caption('監控台') pygame.display.set_icon(icon) #pygame 各鏡頭圖片位置 camPic_pos = { 1: [0, 150], 2: [640, 150], 3: [0, 510], 4: [640, 510] } #pygame 各鏡頭文字位置 camTitle_pos = { 1: [1, 160], 2: [650, 160], 3: [10, 520], 4: [650, 520] } cam_title = { 1: pygame.image.load('images/cam1_title.png'), 2: pygame.image.load('images/cam2_title.png'), 3: pygame.image.load('images/cam3_title.png'), 4: pygame.image.load('images/cam4_title.png') } #初始畫面 icon_color = pygame.image.load('images/icon_color.png') icon = pygame.transform.scale(icon_color, (300, 300)) screen.blit(icon, (160, 230)) #pygame 文字位置 font_title = pygame.font.Font('fonts/NotoSansCJKtc-Regular.otf', 40) font_init_message = pygame.font.Font('fonts/NotoSansCJKtc-Regular.otf',80) #起始訊息 init_message = font_init_message.render("監控系統啟動中", True, (255, 255, 255)) screen.blit(init_message, (450, 350)) #地址 district = font_title.render("新北市 新莊區", True, (255, 255, 0)) street = font_title.render("中正路/建國一路 交叉口", True, (0, 255, 0)) screen.blit(district, (10, 10)) screen.blit(street, (10, 70)) #模式 rule_status_title = font_title.render("號誌控制模式: ", True, (255, 255, 255)) rule_status = font_title.render("手動", True, (255, 0, 0)) screen.blit(rule_status_title, (840, 10)) screen.blit(rule_status, (1100, 10)) #推播 notify_status_title = font_title.render("推播功能: ", True, (255, 255, 255)) notify_status = font_title.render("關閉", True, (255, 0, 0)) screen.blit(notify_status_title, (920, 70)) screen.blit(notify_status, (1100, 70)) #更新畫面 pygame.display.update() #PIL draw on picture pilFont = ImageFont.truetype("fonts/NotoSansCJKtc-Regular.otf", 40) def pygame_event(): global OPEN_NOTIFY global OPEN_RULE for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() elif event.type == pygame.MOUSEBUTTONUP: pos = pygame.mouse.get_pos() #符合點擊區域 if (pos[0] > 1100 and pos[0] < 1200): #規則 if (pos[1] > 0 and pos[1] < 60): screen.fill(pygame.Color("black"), (1100, 0, 1500, 65)) if (OPEN_RULE == True): OPEN_RULE = False rule_status = font_title.render("手動", True, (255, 0, 0)) screen.blit(rule_status, (1100, 10)) print("close rule") else: OPEN_RULE = True rule_status = font_title.render("自動", True, (255, 255, 0)) screen.blit(rule_status, (1100, 10)) print("open rule") return True #通知 elif (pos[1] > 60 and pos[1] < 120): screen.fill(pygame.Color("black"), (1100, 70, 1500, 120)) if (OPEN_NOTIFY == True): OPEN_NOTIFY = False notify_status = font_title.render("關閉", True, (255, 0, 0)) screen.blit(notify_status, (1100, 70)) print("close notify") else: OPEN_NOTIFY = True notify_status = font_title.render("開啟", True, (255, 255, 0)) screen.blit(notify_status, (1100, 70)) print("open notify") return True return False def sns(message): print("發sns") print(message) print(type(message)) sns = boto3.client( 'sns', aws_access_key_id="yourAccessKey", aws_secret_access_key="yourSecretAccessKey", aws_session_token='yourToken', region_name='yourRegion', ) sns.publish( TopicArn='yourARNTopic', Message = message ) return None def lineNotify(token, msg, camID): headers = { "Authorization": "Bearer " + token, } payload = {'message': msg} if (camID == 0): try: session = requests.Session() r = session.post("https://notify-api.line.me/api/notify", headers = headers, params = payload, timeout=3) print(r.status_code) print("success(pure message)") return None except: print("error(pure message)") return None url = "C:/Users/Darkflow/Desktop/darkflow/cars/cam"+str(camID)+".jpg" imageFile = {'imageFile': open(url, 'rb')} try: session = requests.Session() r = session.post("https://notify-api.line.me/api/notify", headers = headers, params = payload, files=imageFile, timeout=3) return r.content except: return None def isHardwareAlive(): try: get_second = requests.get("http://192.168.50.126/", timeout=3) print("hardware health") return True except: print('Hardware Failed') return False def hardwareHealthCheck(): #硬體無回應 if not isHardwareAlive(): if (OPEN_NOTIFY): #laravel 產生維修單 try: headers = {'authorization': "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjFcL2FwaVwvYXV0aFwvbG9naW4iLCJpYXQiOjE1NTgzNDk5MTcsImV4cCI6MTU2Njk4OTkxNywibmJmIjoxNTU4MzQ5OTE3LCJqdGkiOiIxUlNTUlEwU0xDTFhHbEVGIiwic3ViIjoxLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Q42vS5ZghcT4uRAFccoQIZfBWHBBx8vLJ-BjYkuQDQY"} payload = {'intersections_id': 1, 'content': '[A01]硬體控制器異常'} maintenance = requests.post(maintenance_url, headers = headers, params=payload) response_data = json.loads(maintenance.text) #代表維修單正常生成,未重複 if (response_data["notify"] == 1): #發sns try: sns("[A01]硬體控制器異常") except: print("sns error(hardware)") #發line notify message = '錯誤事件:[A01]硬體控制器無回應' print(lineNotify(token, message, 0)) except: print('Laravel API Timeout(hardware maintenance)') return None def getCarCount(url, cam_id): try: r = requests.get(url, timeout=3) except: #計算錯誤次數 error_count_dict["cam"+str(cam_id)] += 1 #鏡頭無回應 print("camID:", cam_id, " timeout.") #錯誤次數達 3 次 if (error_count_dict["cam"+str(cam_id)] >= 4): #顯示"warning"圖片 screen.blit(warning, camPic_pos[cam_id]) screen.blit(cam_title[cam_id], camTitle_pos[cam_id]) #顯示標題 pygame.display.flip() #推播 if (OPEN_NOTIFY): #laravel 產生維修單 try: headers = {'authorization': "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjFcL2FwaVwvYXV0aFwvbG9naW4iLCJpYXQiOjE1NTgzNDk5MTcsImV4cCI6MTU2Njk4OTkxNywibmJmIjoxNTU4MzQ5OTE3LCJqdGkiOiIxUlNTUlEwU0xDTFhHbEVGIiwic3ViIjoxLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.Q42vS5ZghcT4uRAFccoQIZfBWHBBx8vLJ-BjYkuQDQY"} payload = {'intersections_id': 1, 'content': '[C01]鏡頭1無回應'} url = "C:/Users/Darkflow/Desktop/darkflow/cars/cam"+str(cam_id)+".jpg" imageFile = {'imageFile': open(url, 'rb')} maintenance = requests.post(maintenance_url, headers = headers, params=payload, files = imageFile) response_data = json.loads(maintenance.text) #代表維修單正常生成,未重複 if (response_data["notify"] == 1): #發sns try: sns("[C01]鏡頭1無回應") except: print("sns error") #發line notify message = '[C01]鏡頭1無回應' print(lineNotify(token, message, cam_id)) except: print('Laravel API Timeout(maintenance)') #錯誤次數未達3次 elif (error_count_dict["cam"+str(cam_id)] == 2): #顯示"waiting"圖片 screen.blit(waiting, camPic_pos[cam_id]) screen.blit(cam_title[cam_id], camTitle_pos[cam_id]) #顯示標題 pygame.display.flip() return 0 #成功取得影像,刷新錯誤次數 error_count_dict["cam"+str(cam_id)] = 0 #影像處理 curr_img = Image.open(BytesIO(r.content)) curr_img_cv2 = cv2.cvtColor(np.array(curr_img), cv2.COLOR_RGB2BGR) #辨識物體 result = tfnet.return_predict(curr_img_cv2) #影像轉 PIL ImageDraw Object draw = ImageDraw.Draw(curr_img) #圈出物體位置 cars = drawCar(draw, result) #保存畫完的圖片到 local curr_img.save('cars/cam%d.jpg' %(cam_id)) #在pygame顯示圖片 image = pygame.image.load('cars/cam{}.jpg'.format(cam_id)) #讀取上一行保存的圖片 picture = pygame.transform.scale(image, (640, 360)) #調整圖片尺寸 screen.blit(picture, camPic_pos[cam_id]) #放到screen screen.blit(cam_title[cam_id], camTitle_pos[cam_id]) #顯示標題 pygame.display.update() #更新畫面 message = "鏡頭"+str(cam_id)+"偵測到車輛:"+str(cars)+"台" print("camera %d: %d cars detected"%(cam_id, cars)) #存入車輛數 count_dict["cam"+str(cam_id)] = cars return None def drawCar(image, result): carsSeen = 0 for detection in result: if detection['label'] == 'car' : #curr_img.save('cars/%i.jpg' %calculator) x_range = detection['bottomright']['x'] - detection['topleft']['x'] if (x_range < 300): carsSeen += 1 if detection['label'] == 'car': image.rectangle([detection['topleft']['x'], detection['topleft']['y'], detection['bottomright']['x'], detection['bottomright']['y']], outline=(99, 54, 254), width=5) image.rectangle([detection['topleft']['x'], detection['topleft']['y'] - 42, detection['topleft']['x'] + 80, detection['topleft']['y']], fill=(99, 54, 254)) else: #motorbike image.rectangle([detection['topleft']['x'], detection['topleft']['y'], detection['bottomright']['x'], detection['bottomright']['y']], outline=(255, 255, 0), width=5) image.rectangle([detection['topleft']['x'], detection['topleft']['y'] - 42, detection['topleft']['x'] + 200, detection['topleft']['y']], fill=(255, 255, 0)) image.text((detection['topleft']['x'] + 8, detection['topleft']['y'] - 48), detection['label'], font=pilFont, fill=(0,0,0,255)) return carsSeen def detectAndCount(): que = queue.Queue(); thread_list = list(); cam_1 = threading.Thread(target=lambda q, arg1, arg2: q.put(getCarCount(arg1, arg2)), args=(que, 'http://192.168.50.172:5000/image', 1)) cam_2 = threading.Thread(target=lambda q, arg1, arg2: q.put(getCarCount(arg1, arg2)), args=(que, 'http://192.168.50.172:5001/image', 2)) cam_3 = threading.Thread(target=lambda q, arg1, arg2: q.put(getCarCount(arg1, arg2)), args=(que, 'http://192.168.50.206:5002/image', 3)) cam_4 = threading.Thread(target=lambda q, arg1, arg2: q.put(getCarCount(arg1, arg2)), args=(que, 'http://192.168.50.206:5003/image', 4)) cam_1.start() thread_list.append(cam_1); cam_2.start() thread_list.append(cam_2); cam_3.start() thread_list.append(cam_3); cam_4.start() thread_list.append(cam_4); for t in thread_list: t.join() while que.qsize() != 4: continue que.get() que.get() que.get() que.get() print("cam1:", count_dict["cam1"]) print("cam2:", count_dict["cam2"]) print("cam3:", count_dict["cam3"]) print("cam4:", count_dict["cam4"]) return None def judgeRule(isOPENRULE, l1_car, l2_car, l3_car, l4_car): if isOPENRULE: judgeURL = "http://127.0.0.1/judgeRule/1/{light1}/{light2}/{light3}/{light4}/1".format(light1=l1_car, light2=l2_car, light3=l3_car, light4=l4_car) # lineNotify(_token, '中正路/建國一路交叉口 已套用規則', 0) else: judgeURL = "http://127.0.0.1/judgeRule/1/{light1}/{light2}/{light3}/{light4}/0".format(light1=l1_car, light2=l2_car, light3=l3_car, light4=l4_car) try: currentRule = requests.get(judgeURL, timeout=2) result = "Rule Judge: {id}".format(id=currentRule.content) print(result) return result except: err = "Laravel API Timeout(judge rule)" print(err) return err def main(): global lastUpdated global timegap while True: #如果pygame發生事件 if pygame_event(): #更新畫面 pygame.display.flip() #執行排程任務 if (int(round(time.time())) - lastUpdated > timegap): #辨識車輛數 detectAndCount() #規則比較 judge = threading.Thread(target = judgeRule, args=[OPEN_RULE, count_dict["cam1"], count_dict["cam2"], count_dict["cam3"], count_dict["cam4"]]) judge.start() #重置計時器 lastUpdated = int(round(time.time())) #硬體健康檢測 hardwareHealthCheck() if __name__ == '__main__': main() ```