From 57310a38f28c75483a3fd4d8e7f376305339aa9d Mon Sep 17 00:00:00 2001
From: Bigsk <xiaxinzhe@xiaxinzhe.cn>
Date: Sun, 27 Dec 2020 01:11:26 +0800
Subject: [PATCH] UPDATE

---
 GhinkAPI.py                                   |   0
 Server.py                                     | 109 ++++++++++++
 TCPServer.py                                  |   0
 libraries/Astronomy.py                        | 161 ++++++++++++++++++
 libraries/Calendar.py                         |   0
 .../__pycache__/Astronomy.cpython-36.pyc      | Bin 0 -> 7984 bytes
 6 files changed, 270 insertions(+)
 delete mode 100644 GhinkAPI.py
 create mode 100644 Server.py
 delete mode 100644 TCPServer.py
 create mode 100644 libraries/Astronomy.py
 delete mode 100644 libraries/Calendar.py
 create mode 100644 libraries/__pycache__/Astronomy.cpython-36.pyc

diff --git a/GhinkAPI.py b/GhinkAPI.py
deleted file mode 100644
index e69de29..0000000
diff --git a/Server.py b/Server.py
new file mode 100644
index 0000000..57c19df
--- /dev/null
+++ b/Server.py
@@ -0,0 +1,109 @@
+import socket,threading,os,time,math,json,sys,urllib,requests
+sys.path.append('libraries\\')
+from Astronomy import *
+#-------------------------------------#
+#Define Area
+class APICore(object):
+    HTTPHead={
+            '200':'HTTP/1.1 200 OK\r\nServer: SparkE/Alpha1.0\r\nContent-Type: application/json; charset=utf-8\r\n\r\n',
+            '400':'HTTP/1.1 400 BAD REQUEST\r\nServer: SparkE/Alpha1.0\r\nContent-Type: application/json; charset=utf-8\r\n\r\n',
+            '404':'HTTP/1.1 404 NOT FOUND\r\nServer: SparkE/Alpha1.0\r\nContent-Type: application/json; charset=utf-8\r\n\r\n'
+            }
+    def __init__(self):
+        self.__Log=[]
+    def Log(self,IP,Port,Type,Text):
+        Time=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
+        self.__Log.append((Time,IP,Port,Type,Text))
+        print("["+Type+"]["+Time+"]["+IP+"]["+str(Port)+"]"+str(Text))
+    def IsJson(self,text):
+        try:
+            json.loads(text)
+            return True
+        except:
+            return False
+    def Error400(self,sock,addr):
+        sock.send(self.HTTPHead['400'].encode("utf-8"))
+        Result=json.dumps({"info":"bad request","code":400})
+        self.Log(addr[0],addr[1],"SEND",Result)
+        sock.send(str(Result).encode("utf-8"))
+    def SunAzEl(self,sock,addr):
+        sock.send(self.HTTPHead['200'].encode("utf-8"))
+        Result=json.dumps(Astronomy().calcSunAzEl())
+        self.Log(addr[0],addr[1],"SEND",Result)
+        sock.send(str(Result).encode("utf-8"))
+#-------------------------------------#
+API=APICore()
+#-------------------------------------#
+RequestRecord={}
+server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
+server.bind(("0.0.0.0",8000))
+server.listen()
+def socket(sock,addr):
+    while True:
+        try:
+            data = sock.recv(1024)
+            API.Log(addr[0],addr[1],"RECV","Received a request.")
+            #print(data.decode("utf-8"))
+            if("HTTP/" in data.decode("utf-8")):
+                #HTTP Request.
+                HTTPRequestHead=data.decode("utf-8").split("\r\n")[0].split(" ")[1].split("/")
+                del HTTPRequestHead[0]
+                for i in range(0,len(HTTPRequestHead)):
+                    HTTPRequestHead[i]=urllib.parse.unquote(HTTPRequestHead[i])
+                API.Log(addr[0],addr[1],"RECV",HTTPRequestHead)
+                if(" / " in data.decode("utf-8")):
+                    sock.send(API.HTTPHead['200'].encode("utf-8"))
+                    Result=json.dumps({"wikis":"https://gitee.com/ghink/api/wikis"})
+                    API.Log(addr[0],addr[1],"SEND",Result)
+                    sock.send(str(Result).encode("utf8"))
+                    break
+                elif(" /SunAzEl" in data.decode("utf-8")):
+                    if("GET " in data.decode("utf-8")):
+                        try:
+                            HTTPRequestHead[1]
+                            if(API.IsJson(HTTPRequestHead[1])):
+                                API.SunAzEl(sock,addr)
+                            else:
+                                API.Error400(sock,addr)
+                        except:
+                            API.SunAzEl(sock,addr)
+                    elif("POST " in data.decode("utf-8")):
+                        try:
+                            HTTPRequestHead[1]
+                            API.Error400(sock,addr)
+                        except:
+                            API.SunAzEl(sock,addr)
+                    break
+                else:
+                    sock.send(API.HTTPHead['404'].encode("utf8"))
+                    Result=json.dumps({"info":"not found","code":404})
+                    API.Log(addr[0],addr[1],"SEND",Result)
+                    sock.send(Result.encode("utf-8"))
+                    break
+            else:
+                #TCP Request.
+                if(data.decode("utf-8")=="Help" or data.decode("utf-8")=="HELP" or data.decode("utf-8")=="help" or data.decode("utf-8")=="WIKI" or data.decode("utf-8")=="wiki" or data.decode("utf-8")=="wikis" or data.decode("utf-8")=="WIKIS" or data.decode("utf-8")=="?"):
+                    Result=json.dumps({"wikis":"https://gitee.com/ghink/api/wikis"})
+                    API.Log(addr[0],addr[1],"SEND",Result)
+                    sock.send(str(Result).encode("utf8"))
+                elif(data.decode("utf-8")=="SunAzEl"):
+                    Result=json.dumps(Astronomy().calcSunAzEl())
+                    API.Log(addr[0],addr[1],"SEND",Result)
+                    sock.send(str(Result).encode("utf-8"))
+                else:
+                    Result=json.dumps({"info":"not found","code":404})
+                    API.Log(addr[0],addr[1],"SEND",Result)
+                    sock.send(Result.encode("utf-8"))
+        except (ConnectionResetError,ConnectionAbortedError):
+            API.Log(addr[0],addr[1],"STATUS","Lost connection.")
+            break
+        except UnicodeDecodeError:
+            API.Log(addr[0],addr[1],"STATUS","Wrong code mode,must be utf-8.")
+            API.Log(addr[0],addr[1],"STATUS","Lost connection.")
+            break
+def main():
+    sock,addr=server.accept()
+    client_thread=threading.Thread(target=socket,args=(sock,addr))
+    client_thread.start()
+while True:
+    main()
diff --git a/TCPServer.py b/TCPServer.py
deleted file mode 100644
index e69de29..0000000
diff --git a/libraries/Astronomy.py b/libraries/Astronomy.py
new file mode 100644
index 0000000..7ba8bc6
--- /dev/null
+++ b/libraries/Astronomy.py
@@ -0,0 +1,161 @@
+import os,time,math
+#-------------------------------------#
+class Astronomy(object):
+    def calcSunDeclination(self,Stamp=None,TimeZone=8):
+        MonthList = [
+        {"name": 'January',   "numdays": 31},
+        {"name": 'February',  "numdays": 28},
+        {"name": 'March',     "numdays": 31},
+        {"name": 'April',     "numdays": 30},
+        {"name": 'May',       "numdays": 31},
+        {"name": 'June',      "numdays": 30},
+        {"name": 'July',      "numdays": 31},
+        {"name": 'August',    "numdays": 31},
+        {"name": 'September', "numdays": 30},
+        {"name": 'October',   "numdays": 31},
+        {"name": 'November',  "numdays": 30},
+        {"name": 'December',  "numdays": 31},
+        ]
+        if(Stamp==None):
+            TimeStamp = time.time()
+        else:
+            TimeStamp = Stamp
+        Year=int(time.strftime("%Y",time.localtime(TimeStamp)))
+        Month=int(time.strftime("%m",time.localtime(TimeStamp)))
+        Day=int(time.strftime("%d",time.localtime(TimeStamp)))
+        Hour=int(time.strftime("%H",time.localtime(TimeStamp)))
+        Minute=int(time.strftime("%M",time.localtime(TimeStamp)))
+        Second=int(time.strftime("%S",time.localtime(TimeStamp)))
+        if(((Year % 4 == 0 and Year % 100 != 0) or Year % 400 == 0) and (Month == 2)):
+            if(Day > 29):
+                Day=29
+        else:
+            if(Day > MonthList[Month-1]['numdays']):
+                Day = MonthList[Month-1]['numdays']
+        if(Month <= 2):
+            Year -= 1
+            Month += 12
+        L0 = 280.46646 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (36000.76983 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (0.0003032))
+        while(L0 > 360.0):
+            L0 -= 360.0
+        while(L0 < 0.0):
+            L0 += 360.0
+        return (math.degrees(math.asin(math.sin(math.radians(23 + (26 + ((21.448 - ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (46.8150 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (0.00059 - ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (0.001813)))) / 60.0)) / 60.0 + 0.00256 * math.cos(math.radians(1254 - 1934.136 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525))))) * math.sin(math.radians(L0 + math.sin(math.radians(357.52911 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (359995029 - 0.0001537 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525)))) * (1.914602 - ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (0.004817 + 0.000014 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525))) + math.sin(math.radians(357.52911 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (359995029 - 0.0001537 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525))) * 2) * (0.019993 - 0.000101 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525)) + math.sin(math.radians(357.52911 + ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525) * (359995029 - 0.0001537 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525))) * 3) * 0.000289 - 0.00569 - 0.00478 * math.sin(math.radians(1254 - 1934.136 * ((math.floor(365.25 * (Year + 4716)) + math.floor(30.6001 * (Month + 1)) + Day + 2 - math.floor(Year / 100) + math.floor(math.floor(Year / 100) / 4) - 1524.5 + (Hour * 60 + Minute + Second/60.0) / 1440.0 - TimeZone / 24 - 2451545) / 36525))))))) * 100 + 0.5) / 100.0
+    def calcHourAngle(self,Stamp=None,Lon=120,TimeZone=8):
+        MonthList = [
+        {"name": 'January',   "numdays": 31},
+        {"name": 'February',  "numdays": 28},
+        {"name": 'March',     "numdays": 31},
+        {"name": 'April',     "numdays": 30},
+        {"name": 'May',       "numdays": 31},
+        {"name": 'June',      "numdays": 30},
+        {"name": 'July',      "numdays": 31},
+        {"name": 'August',    "numdays": 31},
+        {"name": 'September', "numdays": 30},
+        {"name": 'October',   "numdays": 31},
+        {"name": 'November',  "numdays": 30},
+        {"name": 'December',  "numdays": 31},
+        ]
+        if(Stamp==None):
+            TimeStamp = time.time()
+        else:
+            TimeStamp = Stamp
+        Year=int(time.strftime("%Y",time.localtime(TimeStamp)))
+        Month=int(time.strftime("%m",time.localtime(TimeStamp)))
+        Day=int(time.strftime("%d",time.localtime(TimeStamp)))
+        Hour=int(time.strftime("%H",time.localtime(TimeStamp)))
+        Minute=int(time.strftime("%M",time.localtime(TimeStamp)))
+        Second=int(time.strftime("%S",time.localtime(TimeStamp)))
+        if(((Year % 4 == 0 and Year % 100 != 0) or Year % 400 == 0) and (Month == 2)):
+            if(Day > 29):
+                Day=29
+        else:
+            if(Day > MonthList[Month-1]['numdays']):
+                Day = MonthList[Month-1]['numdays']
+        if(Month <= 2):
+            Year -= 1
+            Month += 12
+        TimeJulianCent = (math.floor(365.25*(Year + 4716)) + math.floor(30.6001*(Month+1)) + Day + 2 - math.floor(Year/100) + math.floor(math.floor(Year/100)/4) - 1524.5 + Hour * 60 + Minute + Second/60.0/1440.0 - TimeZone/24 - 2451545)/36525
+        L0 = 280.46646 + TimeJulianCent * (36000.76983 + TimeJulianCent *(0.0003032))
+        while(L0 > 360.0):
+            L0 -= 360.0
+        while(L0 < 0.0):
+            L0 += 360.0
+        TrueSolarTime = (Hour * 60 + Minute + Second / 60) + ((4 * math.degrees((math.tan(math.radians((23 + (26 + ((21.448 - TimeJulianCent * (46.8150 + TimeJulianCent * (0.00059 - TimeJulianCent * (0.001813)))) / 60.0)) / 60.0 + 0.00256 * math.cos(math.radians(1254 - 1934.136 * TimeJulianCent))))/2) ** 2) * math.sin(2 * math.radians(L0)) - 2 * (0.016708634 - TimeJulianCent * (0.000042037 + 0.0000001267 * TimeJulianCent)) * math.sin(math.radians(357.52911 + TimeJulianCent * (359995029 - 0.0001537 * TimeJulianCent))) + 4 * (0.016708634 - TimeJulianCent * (0.000042037 + 0.0000001267 * TimeJulianCent)) * (math.tan(math.radians((23 + (26 + ((21.448 - TimeJulianCent * (46.8150 + TimeJulianCent * (0.00059 - TimeJulianCent * (0.001813)))) / 60.0)) / 60.0 + 0.00256 * math.cos(math.radians(1254 - 1934.136 * TimeJulianCent)))) / 2) ** 2) * math.sin(math.radians(357.52911 + TimeJulianCent * (359995029 - 0.0001537 * TimeJulianCent))) * math.cos(2 * math.radians(L0)) - 0.5 * (math.tan(math.radians((23 + (26 + ((21.448 - TimeJulianCent * (46.8150 + TimeJulianCent * (0.00059 - TimeJulianCent * (0.001813)))) / 60.0)) / 60.0 + 0.00256 * math.cos(math.radians(1254 - 1934.136 * TimeJulianCent))))/2) ** 2) * (math.tan(math.radians((23 + (26 + ((21.448 - TimeJulianCent * (46.8150 + TimeJulianCent * (0.00059 - TimeJulianCent * (0.001813)))) / 60.0)) / 60.0 + 0.00256 * math.cos(math.radians(1254 - 1934.136 * TimeJulianCent))))/2) ** 2) * math.sin(4 * math.radians(L0)) - 1.25 * ((0.016708634 - TimeJulianCent * (0.000042037 + 0.0000001267 * TimeJulianCent)) ** 2) * math.sin(2 * math.radians(math.radians(357.52911 + TimeJulianCent * (359995029 - 0.0001537 * TimeJulianCent)))))) + 4 * Lon - 60.0 * TimeZone)
+        while (TrueSolarTime > 1440):
+            TrueSolarTime -= 1440
+        HourAngle = TrueSolarTime / 4 - 180.0
+        if (HourAngle < -180):
+            HourAngle += 360.0
+        return HourAngle
+    def calcSunAzEl(self,Stamp=None,Lon=120,Lat=30,TimeZone=8,ZeroAzimuth="North"):
+        MonthList = [
+        {"name": 'January',   "numdays": 31},
+        {"name": 'February',  "numdays": 28},
+        {"name": 'March',     "numdays": 31},
+        {"name": 'April',     "numdays": 30},
+        {"name": 'May',       "numdays": 31},
+        {"name": 'June',      "numdays": 30},
+        {"name": 'July',      "numdays": 31},
+        {"name": 'August',    "numdays": 31},
+        {"name": 'September', "numdays": 30},
+        {"name": 'October',   "numdays": 31},
+        {"name": 'November',  "numdays": 30},
+        {"name": 'December',  "numdays": 31},
+        ]
+        if(Stamp==None):
+            TimeStamp = time.time()
+        else:
+            TimeStamp = Stamp
+        Year=int(time.strftime("%Y",time.localtime(TimeStamp)))
+        Month=int(time.strftime("%m",time.localtime(TimeStamp)))
+        Day=int(time.strftime("%d",time.localtime(TimeStamp)))
+        Hour=int(time.strftime("%H",time.localtime(TimeStamp)))
+        Minute=int(time.strftime("%M",time.localtime(TimeStamp)))
+        Second=int(time.strftime("%S",time.localtime(TimeStamp)))
+        if(((Year % 4 == 0 and Year % 100 != 0) or Year % 400 == 0) and (Month == 2)):
+            if(Day > 29):
+                Day=29
+        else:
+            if(Day > MonthList[Month-1]['numdays']):
+                Day = MonthList[Month-1]['numdays']
+        if(Month <= 2):
+            Year -= 1
+            Month += 12
+        ZeroAzimuth=180 if(ZeroAzimuth=="South") else 0
+        csz = math.sin(math.radians(Lat)) * math.sin(math.radians(self.calcSunDeclination(Stamp,TimeZone))) + math.cos(math.radians(Lat)) * math.cos(math.radians(self.calcSunDeclination(Stamp,TimeZone))) * math.cos(math.radians(self.calcHourAngle(Stamp,Lon,TimeZone)))
+        if(csz > 1):
+            csz = 1
+        elif(csz < -1):
+            csz = -1
+        if(abs((math.cos(math.radians(Lat)) * math.sin(math.radians(math.degrees(math.acos(csz)))))) > 0.001):
+            azRad = ((math.sin(math.radians(Lat)) * math.cos(math.radians(math.degrees(math.acos(csz))))) - math.sin(math.radians(self.calcSunDeclination(Stamp,TimeZone)))) / (math.cos(math.radians(Lat)) * math.sin(math.radians(math.degrees(math.acos(csz)))))
+            if(abs(azRad) > 1.0):
+                if(azRad < 0):
+                    azRad = -1.0
+                else:
+                    azRad = 1.0
+            azimuth = 180.0 - math.degrees(math.acos(azRad))
+            if(self.calcHourAngle(Stamp,Lon,TimeZone) > 0.0):
+                azimuth = -azimuth
+        else:
+            if(Lat > 0.0):
+                azimuth = 180.0
+            else:
+                azimuth = 0.0
+        if(azimuth < 0.0):
+            azimuth += 360.0
+        exoatmElevation = (90.0 - math.degrees(math.acos(csz)))
+        if (exoatmElevation > 85.0):
+            refractionCorrection = 0.0
+        else:
+            te = math.tan (math.radians(exoatmElevation))
+            if (exoatmElevation > 5.0):
+                refractionCorrection = 58.1 / te - 0.07 / (te*te*te) + 0.000086 / (te*te*te*te*te)
+            elif (exoatmElevation > -0.575):
+                refractionCorrection = 1735.0 + exoatmElevation * (-518.2 + exoatmElevation * (103.4 + exoatmElevation * (-12.79 + exoatmElevation * 0.711) ) )
+            else:
+                refractionCorrection = -20.774 / te
+            refractionCorrection = refractionCorrection / 3600.0
+        solarZen = math.degrees(math.acos(csz)) - refractionCorrection
+        return {"az":((azimuth*100 +0.5) - (ZeroAzimuth*100))/100.0,"el":((90.0-solarZen)*100+0.5)/100.0}
\ No newline at end of file
diff --git a/libraries/Calendar.py b/libraries/Calendar.py
deleted file mode 100644
index e69de29..0000000
diff --git a/libraries/__pycache__/Astronomy.cpython-36.pyc b/libraries/__pycache__/Astronomy.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..41491c9e4241dd49eb165dc80311dace505ecec3
GIT binary patch
literal 7984
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
Bx@!Oc

literal 0
HcmV?d00001