from opcua import Client
import numpy as np
from opcua import ua

## METHODS

# Method for connecting to the server
# Need of entering URL
def connectToServer(url):
    try:
        client.connect()
        print("Client connected")
        return True
    except:
        print("Connecting issue")

# Method for disconnectinf from the server
def disconnectFromServer():
    try:
        client.disconnect()
        print("Client disconnected")
    except:
        print("Disconnecting issue")

# Method for finding first subnodes
def subNodesList():
    try:
        objects = client.get_objects_node()
        subNodes = objects.get_children()
    
        for subNode in subNodes:
            print("     SubNode name: ", subNode.get_browse_name())
    except Exception as ex:
        print(str(ex))

# Method for finding all (sub)nodes
def allNodesList():
    try:
        objects = client.get_objects_node()
        sub1Nodes = objects.get_children()

        for sub1Node in sub1Nodes:
            print("     First leyer of SubNodes name: ", sub1Node.get_browse_name())
            sub2Nodes = sub1Node.get_children()
            for sub2Node in sub2Nodes:
                print("         Second leyer of SubNodes name: ", sub2Node.get_browse_name())
                sub3Nodes = sub2Node.get_children()
                for sub3Node in sub3Nodes:
                    print("            Third leyer of SubNodes name: ", sub3Node.get_browse_name())
                    sub4Nodes = sub3Node.get_children()
                    for sub4Node in sub4Nodes:
                        print("                Fourth leyer of SubNodes name: ", sub4Node.get_browse_name())
                        sub5Nodes = sub4Node.get_children()
                        for sub5Node in sub5Nodes:
                            print("                    Fifth leyer of SubNodes name: ", sub5Node.get_browse_name())
    except Exception as ex:
        print(str(ex))

# Method for reading a node value
# Node is chosen based on its nodeID
def readValue_id(id):
    try:
        node = client.get_node(id)
        print("Value of " + id + " is " + str(node.get_value()))
    except Exception as ex:
        print(str(ex))

# Method for rewriting a node value
# Node is chosen based on its nodeID
def writeValue_id(id, newValue):
    try:
        node = client.get_node(id)
        print("Fomer value: ", str(node.get_value()))
        node.set_value(ua.Variant(np.uint16(newValue), ua.VariantType.Int16))
        print("New value: " + str(node.get_value()))
    except Exception as ex:
        print(str(ex))


## PROGRAM
if __name__== "__main__":
    print("OPC Unified Architecture Client")
    print()

    # Input for URL + declaring new Client object
    print("Enter server URL: ")
    url = input()
    client = Client(url)

    connectionState = connectToServer(url)
    try:
        # If connected to a server, this loop runs
        # User can choose one of the actions
        # to choose an action, user has to enter a number of it
        # Program ends when an action "Disconnecting" is chosen
        while connectionState:
            print()
            print("Choose action: \n 1 List of subnodes \n 2 List of all nodes \n 3 Read value of a node (nodeId) \n 4 Read value of a node (name) \n 5 Write new value \n 6 Disconnect")
            print()
            action = input()
            print()

            if action == "1":
                subNodesList()
                
            elif action ==  "2":
                allNodesList()
                
            elif action == "3":
                print("Enter node id: ")
                id = input()
                readValue_id(id)
                
            elif action == "4":
                print("Enter node name: ")
                name = input()
                readValue_name(name)
                
            elif action == "5":
                print("Enter node id: ")
                id = input()
                print("Enter new value: ")
                newValue = float(input())
                writeValue_id(id, newValue)
        
            elif action == "6":
                disconnectFromServer()
                connectionState = False
                
            else:
                print("choice out of range")
    except:
        pass
