WLAN an Alcatel HH71 Mobil-Router ein/ausschalten

Hardware- und Elektronikbasteleien, Ansteuerung von Schnittstellen und Peripherie.
Fragen zu "Consumer"-Problemen kommen in Offtopic.
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

WLAN an Alcatel HH71 Mobil-Router ein/ausschalten

Beitrag von DePe »

Ich habe den Alcatel HH71VM Mobilfunk-Router (LINKHUB LTE cat7 Home Station) von Magenta (AT). Das 2G-WLAN ist deaktiviert, da ich es nur selten benötige.

Da mir das ein- und ausschalten über das Web-Interface lästig ist, habe ich mir jetzt die Funktionen für HTTP und JSON angeschaut um das ganze zu automatisieren.

Anbei der Code um das WLAN ein- oder auszuschalten, je nach aktuellen Status. Dem Programm muss das Kennwort für die Anmeldung übergeben werden. Eventuell muss noch der Wert für den Header "_TclRequestVerificationKey" für das aktuelle Gerät ermittelt werden.

Peter

Code: Alles auswählen

; Schaltet das 2,4 GHz WLAN am Alcatel Router HH71 aus oder ein, je nach aktuellen Zustand.
; Es wird die unverschlüsselte HTTP-Verbindung verwendet.

EnableExplicit

; Die Debugausgaben funktionieren damit in der kompilierten Exe-Datei für 'DebugView'.
; Macro Debug(sText)
; 	OutputDebugString_(sText)
; EndMacro

Global gfWlanStatus.i, gsJsonResponseError.s, gsJsonGetWlanSettingsResponse.s
Global NewMap gHeaderMap.s()

#sProgramTitle = "WLAN-Ein- oder Ausschalten"
#sIP = "192.168.1.1"
#sUrl = "http://" + #sIP
#sUrlWebApi = #sUrl + "/jrd/webapi"
#sUserName = "admin"

; Der Header "_TclRequestVerificationKey" muss immer mit gesendet werden. Der Wert stammt aus den empfangenen Daten.
; Wahrscheinlich unterscheidet sich der Wert zwischen den Geräten.
#sTclRequestVerificationKey = "KSDHSDFOGQ5WERYTUIQWERTYUISDFG1HJZXCVCXBN2GDSMNDHKVKFsVBNf"


Procedure.s EncryptAdmin(sValue.s)
	Protected sReturn.s, sKey.s, iLen.i, c.i, iValueCode.i, iKeyCode.i, sEncrypted.s
	
	; https://github.com/spolette/Alcatel_HH72

	sKey = "e5dl12XYVggihggafXWf0f2YSf2Xngd1"
	iLen = Len(sValue) - 1
	
	For c = 0 To iLen
		iValueCode = Asc(Mid(sValue, c + 1, 1))
		iKeyCode = Asc(Mid(sKey, Mod(c, Len(sKey)) + 1, 1))
		sEncrypted + Chr(($F0 & iKeyCode) | (($0F & iValueCode) ! ($0F & iKeyCode)))
		sEncrypted + Chr(($F0 & iKeyCode) | ((iValueCode >> 4) ! ($0F & iKeyCode)))
	Next
	
	ProcedureReturn sEncrypted
EndProcedure


Procedure.i GetJsonValue(iJsonValueNumber.i, sObjectName.s, sValueName.s, *usValue.String, *uiType.Integer)
	Protected fResult.i, iReturn.i, sMemberName.s, iObjectNumber.i
	
	*usValue\s = #Null$
	*uiType\i = #PB_Default
	
	fResult = Bool(iJsonValueNumber)
	If Not fResult
		Debug("GetJsonValue Fehler: iJsonValueNumber ist Null.")
	EndIf
	
	If fResult
		fResult = Bool(ExamineJSONMembers(iJsonValueNumber))
		If Not fResult
			Debug("GetJsonValue Fehler: Das JSON-Objekt kann nicht untersucht werden.")
		EndIf
	EndIf
	
	If fResult
		While NextJSONMember(iJsonValueNumber)
			sMemberName = JSONMemberKey(iJsonValueNumber)
			;Debug("sMemberName: " + sMemberName)
			
			If Len(sObjectName)
				If (sMemberName = sObjectName)
					iObjectNumber = JSONMemberValue(iJsonValueNumber)
					;Debug("Rekursiv")
					iReturn = GetJsonValue(iObjectNumber, #Null$, sValueName, *usValue, *uiType)
					Break
				EndIf
				
			ElseIf (sMemberName = sValueName)
				iObjectNumber = JSONMemberValue(iJsonValueNumber)
				*uiType\i = JSONType(iObjectNumber)
				
				Select *uiType\i
					Case #PB_JSON_Null
						*usValue\s = #Null$
					Case #PB_JSON_String
						*usValue\s = GetJSONString(iObjectNumber)
					Case #PB_JSON_Number
						*usValue\s = Str(GetJSONInteger(iObjectNumber))
					Case #PB_JSON_Boolean
						*usValue\s = Str(GetJSONBoolean(iObjectNumber))
					Case #PB_JSON_Array
						*usValue\s = "ArraySize: " + JSONArraySize(iObjectNumber)
					Case #PB_JSON_Object
						*usValue\s = "ObjectSize: " + JSONObjectSize(iObjectNumber)
				EndSelect
				
				iReturn = iObjectNumber
				Break
			EndIf
			
		Wend
	EndIf
	
	ProcedureReturn iReturn
EndProcedure


Procedure.s GetJsonResponseError(iJsonNumber.i)
	Protected sReturn.s, fResult.i, iJsonObjectNumber.i, usValue.String, uiType.Integer, sCode.s, sMessage.s
	
	; Den Fehler ermitteln und zurückgeben.
	; { "jsonrpc": "2.0", "error": { "code": "010101", "message": "Username or Password is not correct." }, "id": "12" }
	
	If iJsonNumber
		iJsonObjectNumber = GetJsonValue(JSONValue(iJsonNumber), "error", "code", usValue, uiType)
		If (iJsonObjectNumber And Len(usValue\s))
			sCode = usValue\s
		EndIf
		iJsonObjectNumber = GetJsonValue(JSONValue(iJsonNumber), "error", "message", usValue, uiType)
		If (iJsonObjectNumber And Len(usValue\s))
			sMessage = usValue\s
		EndIf
			
		sReturn = sMessage + " (" + sCode + ")"
	EndIf
			
	ProcedureReturn sReturn
EndProcedure


Procedure.s CreateJsonMethod(sMethod.s, sPassword.s = #Null$)
	Protected sReturn.s, iJsonNumber.i, iObjectNumber.i
	
	; Die JSON-RPC-Daten erstellen, z.B.:
	; {"id":"12","jsonrpc":"2.0","method":"Login","params":{"UserName":"xxxxx","Password":"xxxxx"}}
	; {"id":"12","jsonrpc":"2.0","method":"GetWlanSettings","params":{}}
	
	iJsonNumber = CreateJSON(#PB_Any)
	iObjectNumber = SetJSONObject(JSONValue(iJsonNumber))

	SetJSONString(AddJSONMember(iObjectNumber, "id"), "12")
	SetJSONString(AddJSONMember(iObjectNumber, "jsonrpc"), "2.0")
	SetJSONString(AddJSONMember(iObjectNumber, "method"), sMethod)
	
	iObjectNumber = AddJSONMember(iObjectNumber, "params")
	SetJSONObject(iObjectNumber)
	
	If (sMethod = "Login")
		SetJSONString(AddJSONMember(iObjectNumber, "UserName"), EncryptAdmin(#sUserName))
		SetJSONString(AddJSONMember(iObjectNumber, "Password"), EncryptAdmin(sPassword))
	EndIf
	
	sReturn = ComposeJSON(iJsonNumber)
	FreeJSON(iJsonNumber)

	ProcedureReturn sReturn
EndProcedure

;-

Procedure.i Login(sPassword.s)
	Protected fReturn.i, fResult.i, iJsonNumber.i, iObjectNumber.i, sJsonRpc.s
	Protected iRequestIdentifier.i, sResponse.s
	Protected usValue.String, uiType.Integer
	
	; Die JSON-RPC-Daten erstellen.
	; {"id":"12","jsonrpc":"2.0","method":"Login","params":{"UserName":"xxxxx","Password":"xxxxx"}}
	sJsonRpc = CreateJsonMethod("Login", sPassword)

	
	; Die Daten für das Anmelden senden.
	gHeaderMap("Content-Length") = Str(StringByteLength(sJsonRpc, #PB_UTF8))
	iRequestIdentifier.i = HTTPRequest(#PB_HTTP_Post, #sUrlWebApi, sJsonRpc, #PB_HTTP_Debug, gHeaderMap())


	; Die Antwort einlesen und das Token ermitteln.
	; { "jsonrpc": "2.0", "result": { "token": 74097316 }, "id": "12" } 
	If iRequestIdentifier
		Debug("Login Response:")
		sResponse = HTTPInfo(iRequestIdentifier, #PB_HTTP_Response, #PB_UTF8)
		Debug(sResponse)
		FinishHTTP(iRequestIdentifier)
		
		iJsonNumber = ParseJSON(#PB_Any, sResponse)
		If iJsonNumber
			iObjectNumber = GetJsonValue(JSONValue(iJsonNumber), "result", "token", usValue, uiType)
			fReturn = Bool(iObjectNumber And Len(usValue\s))
			
			; Das Token zu den Header-Daten hinzufügen.
			If fReturn
				Debug("Login Token: " + usValue\s)
				gHeaderMap("_TclRequestVerificationToken") = EncryptAdmin(usValue\s)
			Else
				gsJsonResponseError = GetJsonResponseError(iJsonNumber)
			EndIf
			
			FreeJSON(iJsonNumber)
		EndIf
	EndIf
	
	ProcedureReturn fReturn
EndProcedure


Procedure.i GetWlanSettings()
	Protected fReturn.i, iJsonNumber.i, iObjectNumber.i, sJsonRpc.s
	Protected iRequestIdentifier.i, sResponse.s
	Protected usValue.String, uiType.Integer
	
	; Die JSON-RPC-Daten erstellen.
	; {"id":"12","jsonrpc":"2.0","method":"GetWlanSettings","params":{}}
	sJsonRpc = CreateJsonMethod("GetWlanSettings")

	
	; Die Daten für die WLAN-Einstellungen senden.
	gHeaderMap("Content-Length") = Str(StringByteLength(sJsonRpc, #PB_UTF8))
	iRequestIdentifier.i = HTTPRequest(#PB_HTTP_Post, #sUrlWebApi, sJsonRpc, #PB_HTTP_Debug, gHeaderMap())


	; Die Antwort einlesen und den Status des WLANs ermitteln.
	; { "jsonrpc": "2.0", "result": { "WiFiOffTime": 0, "AP2G": { "CountryCode": "AT", "ApStatus": 0, "WMode": 3, "Ssid": "WLAN123",
	; "SsidHidden": 0, "Channel": 0, "SecurityMode": 3, "WepType": 0, "WpaType": 1, "WepKey": "xxxxx", "WpaKey": "xxxxx",
	; "ApIsolation": 0, "max_numsta": 5, "curr_num": 0, "CurChannel": 0, "Bandwidth": 0 }, "AP5G": { "CountryCode": "AT", "ApStatus": 0,
	; "WMode": 6, "Ssid": "HH71VM_33C7_5G", "SsidHidden": 0, "Channel": 0, "SecurityMode": 3, "WepType": 0, "WpaType": 1,
	; "WepKey": "xxxxx", "WpaKey": "xxxxx", "ApIsolation": 0, "max_numsta": 32, "curr_num": 0, "CurChannel": 0,
	; "Bandwidth": 4 } }, "id": "12" }
	If iRequestIdentifier
		Debug("GetWlanSettings Response:")
		sResponse = HTTPInfo(iRequestIdentifier, #PB_HTTP_Response, #PB_UTF8)
		Debug(sResponse)
		FinishHTTP(iRequestIdentifier)
		
		iJsonNumber = ParseJSON(#PB_Any, sResponse)
		If iJsonNumber
			iObjectNumber = GetJsonValue(JSONValue(iJsonNumber), "result", "AP2G", usValue, uiType)
			iObjectNumber = GetJsonValue(iObjectNumber, #Null$, "ApStatus", usValue, uiType)
			fReturn = Bool(iObjectNumber And Len(usValue\s))
			
			If fReturn
				gfWlanStatus = Val(usValue\s)
				Debug("GetWlanSettings WLAN-Status: " + gfWlanStatus)
			Else
				gsJsonResponseError = GetJsonResponseError(iJsonNumber)
			EndIf
			
			FreeJSON(iJsonNumber)
			
			; Response sichern für SetWlanSettings().
			gsJsonGetWlanSettingsResponse = sResponse
		EndIf
	EndIf
	
	ProcedureReturn fReturn
EndProcedure


Procedure.i SetWlanSettings()
	Protected fReturn.i, fResult.i, iJsonNumber.i, iObjectNumber.i, sJsonRpc.s
	Protected iRequestIdentifier.i, sResponse.s
	Protected usValue.String, uiType.Integer

	; Die empfangenen WLAN-Daten:
	
	; { "jsonrpc": "2.0", "result": { "WiFiOffTime": 0, "AP2G": { "CountryCode": "AT", "ApStatus": 0, "WMode": 3, "Ssid": "WLAN123",
	; "SsidHidden": 0, "Channel": 0, "SecurityMode": 3, "WepType": 0, "WpaType": 1, "WepKey": "xxxxx", "WpaKey": "xxxxx",
	; "ApIsolation": 0, "max_numsta": 5, "curr_num": 0, "CurChannel": 0, "Bandwidth": 0 }, "AP5G": { "CountryCode": "AT", "ApStatus": 0,
	; "WMode": 6, "Ssid": "HH71VM_33C7_5G", "SsidHidden": 0, "Channel": 0, "SecurityMode": 3, "WepType": 0, "WpaType": 1,
	; "WepKey": "xxxxx", "WpaKey": "xxxxx", "ApIsolation": 0, "max_numsta": 32, "curr_num": 0, "CurChannel": 0,
	; "Bandwidth": 4 } }, "id": "12" }

	; Die gesendeten WLAN-Daten über das Web-Interface:
	
	; {"id":"12","jsonrpc":"2.0","method":"SetWlanSettings","params":{"show2GPassword":false,"show5GPassword":false,
	; "showAP2G_guestPassword":false,"WiFiOffTime":0,"AP2G":{"CountryCode":"AT","ApStatus":1,"WMode":3,"Ssid":"WLAN123",
	; "SsidHidden":0,"Channel":0,"SecurityMode":3,"WepType":0,"WpaType":1,"WepKey":"xxxxx","WpaKey":"xxxxx",
	; "ApIsolation":0,"max_numsta":5,"curr_num":0,"CurChannel":0,"Bandwidth":0},"AP2G_guest":{"ApStatus":0,"WMode":3,
	; "CountryCode":"CN","Ssid":"","SsidHidden":0,"Channel":0,"SecurityMode":3,"WepType":0,"WepKey":"xxxxx","WpaType":1,
	; "WpaKey":"xxxxx","ApIsolation":0,"max_numsta":15,"curr_num":0,"CurChannel":8,"Bandwidth":0},"AP5G":{"CountryCode":"AT",
	; "ApStatus":0,"WMode":6,"Ssid":"HH71VM_33C7_5G","SsidHidden":0,"Channel":0,"SecurityMode":3,"WepType":0,"WpaType":1,
	; "WepKey":"xxxxx","WpaKey":"xxxxx","ApIsolation":0,"max_numsta":32,"curr_num":0,"CurChannel":0,"Bandwidth":4}}}

	; Es genügt die empfangenen WLAN-Einstellungen zu senden, mit dem geänderten WLAN-Status.

	
	fResult = Bool(Len(gsJsonGetWlanSettingsResponse))
	If Not fResult
		Debug("SetWlanSettings Fehler: Die WLAN-Einstellungen sind nicht vorhanden.")
	EndIf
	
	If fResult
		iJsonNumber = ParseJSON(#PB_Any, gsJsonGetWlanSettingsResponse)
		fResult = Bool(iJsonNumber)
		If Not fResult
			Debug("SetWlanSettings Fehler: Das JSON-Objekt konnte nicht mit den eingelesenen WLAN-Daten erstellt werden.")
		EndIf
	EndIf

	If fResult
		; Werte zu den empfangenen WLAN-Daten hinzufügen.
		iObjectNumber = JSONValue(iJsonNumber)
		SetJSONString(AddJSONMember(iObjectNumber, "method"), "SetWlanSettings")
	EndIf
	
	If fResult
		; Den WLAN-Status ändern.
		iObjectNumber = GetJsonValue(iObjectNumber, "result", "AP2G", usValue, uiType)
		fResult = Bool(iObjectNumber)
		If Not fResult
			Debug("SetWlanSettings Fehler: Objekt AP2G ist nicht vorhanden.")
		Else
			iObjectNumber = GetJsonValue(iObjectNumber, #Null$, "ApStatus", usValue, uiType)
			fResult = Bool(iObjectNumber And Len(usValue\s))
			If Not fResult
				Debug("SetWlanSettings Fehler: Member ApStatus ist in Objekt AP2G nicht vorhanden.")
			Else
				SetJSONInteger(iObjectNumber, Bool(Not gfWlanStatus))
				Debug("SetWlanSettings ApStatus: " + GetJSONInteger(iObjectNumber))
			EndIf
		EndIf
	EndIf
	
	If fResult
		; Den Namen des Objekts "result" in "params" ändern.
		; Das Ändern ist anscheinend nicht mit JSON-Funktionen möglich.
		sJsonRpc = ComposeJSON(iJsonNumber)
		fResult = Bool(FindString(sJsonRpc, ~"\"result\""))
		If Not fResult
			Debug("SetWlanSettings Fehler: Das Objekt 'result' ist nicht vorhanden.")
		Else
			ReplaceString(sJsonRpc, ~"\"result\"", ~"\"params\"", #PB_String_InPlace, 1, 1)
			Debug("SetWlanSettings Neue JSON-Daten:")
			Debug(sJsonRpc)
		EndIf
	EndIf

	If iJsonNumber
		FreeJSON(iJsonNumber)
	EndIf
 		
	
	If fResult
		; Die geänderten Daten für die WLAN-Einstellungen senden.
		gHeaderMap("Content-Length") = Str(StringByteLength(sJsonRpc, #PB_UTF8))
		iRequestIdentifier.i = HTTPRequest(#PB_HTTP_Post, #sUrlWebApi, sJsonRpc, #PB_HTTP_Debug, gHeaderMap())
	
		; Die Antwort einlesen und den Erfolg ermitteln.
		; { "jsonrpc": "2.0", "result": { }, "id": "12" }
		If iRequestIdentifier
			Debug("SetWlanSettings Response:")
			sResponse = HTTPInfo(iRequestIdentifier, #PB_HTTP_Response, #PB_UTF8)
			Debug(sResponse)
			FinishHTTP(iRequestIdentifier)
			
			iJsonNumber = ParseJSON(#PB_Any, sResponse)
			If iJsonNumber
				iObjectNumber = GetJsonValue(JSONValue(iJsonNumber), #Null$, "result", usValue, uiType)
				fReturn = Bool(iObjectNumber And Len(usValue\s))
				
				If fReturn
					Debug("SetWlanSettings Erfolgreich")
				Else
					gsJsonResponseError = GetJsonResponseError(iJsonNumber)
				EndIf
				
				FreeJSON(iJsonNumber)
			EndIf
		EndIf
	EndIf
	
	ProcedureReturn fReturn
EndProcedure


Procedure.i Logout()
	Protected fReturn.i, iJsonNumber.i, iObjectNumber.i, sJsonRpc.s
	Protected iRequestIdentifier.i, sResponse.s
	Protected usValue.String, uiType.Integer
	
	; Die JSON-RPC-Daten erstellen.
	; {"id":"12","jsonrpc":"2.0","method":"Logout","params":{}}	
	sJsonRpc = CreateJsonMethod("Logout")

	
	; Die Daten für das Abmelden senden.
	gHeaderMap("Content-Length") = Str(StringByteLength(sJsonRpc, #PB_UTF8))
	iRequestIdentifier.i = HTTPRequest(#PB_HTTP_Post, #sUrlWebApi, sJsonRpc, #PB_HTTP_Debug, gHeaderMap())


	; Die Antwort einlesen und den Erfolg ermitteln.
	; { "jsonrpc": "2.0", "result": { }, "id": "12" }
	If iRequestIdentifier
		Debug("Logout Response:")
		sResponse = HTTPInfo(iRequestIdentifier, #PB_HTTP_Response, #PB_UTF8)
		Debug(sResponse)
		FinishHTTP(iRequestIdentifier)
		
		iJsonNumber = ParseJSON(#PB_Any, sResponse)
		If iJsonNumber
			iObjectNumber = GetJsonValue(JSONValue(iJsonNumber), #Null$, "result", usValue, uiType)
			fReturn = Bool(iObjectNumber And Len(usValue\s))
			
			If fReturn
				Debug("Logout Erfolgreich")
			Else
				gsJsonResponseError = GetJsonResponseError(iJsonNumber)
			EndIf
			
			FreeJSON(iJsonNumber)
		EndIf
	EndIf
	
	ProcedureReturn fReturn
EndProcedure

;-

Procedure Main()
	Protected sPassword.s, fResult.i, fLogin.i

	; Das Kennwort ermitteln.
	fResult = Bool(CountProgramParameters())
	If Not fResult
		MessageRequester(#sProgramTitle, "Es wurde kein Kennwort für die Anmeldung übergeben.", #PB_MessageRequester_Error)
	Else
		sPassword = ProgramParameter(0)
	EndIf
	
	; Header für den HTTPRequest erstellen.
	If fResult
		gHeaderMap("Referer") = #sUrl + "/"
		gHeaderMap("_TclRequestVerificationKey") = #sTclRequestVerificationKey
		gHeaderMap("Content-Type") = "application/json;charset=utf-8"
		gHeaderMap("X-Requested-With") = "XMLHttpRequest"
		gHeaderMap("Origin") = #sUrl
	EndIf
	
	; Anmelden.
	If fResult
		fResult = Login(sPassword)
		fLogin = fResult
		If Not fResult
			MessageRequester(#sProgramTitle, "Fehler bei Anmelden." + #CRLF$ + gsJsonResponseError, #PB_MessageRequester_Error)
		EndIf
	EndIf
	
	; Die Wlan-Einstellungen einlesen und den Status des WLAN ermitteln.
	If fResult
		fResult = GetWlanSettings()
		If Not fResult
			MessageRequester(#sProgramTitle, "Fehler bei WLAN-Einstellungen einlesen." + #CRLF$ + gsJsonResponseError,
				#PB_MessageRequester_Error)
		EndIf
	EndIf
	
	; Die WLAN-Einstellung für AP2G ändern und die Einstellungen senden.
	If fResult
		fResult = SetWlanSettings()
		If Not fResult
			MessageRequester(#sProgramTitle, "Fehler bei WLAN-Einstellungen ändern." + #CRLF$ + gsJsonResponseError,
				#PB_MessageRequester_Error)
		EndIf
	EndIf
	
	; Abmelden.
	If fLogin
		fResult = Logout()
		If Not fResult
			MessageRequester(#sProgramTitle, "Fehler bei Abmelden." + #CRLF$ + gsJsonResponseError, #PB_MessageRequester_Error)
		EndIf
	EndIf
	
EndProcedure

;- Start

Main()