File size: 3,426 Bytes
f994803
 
f7ba937
f994803
 
 
 
 
 
 
 
 
f7ba937
f994803
6837238
f994803
 
 
 
f7ba937
f994803
 
 
f7ba937
 
f994803
f7ba937
f994803
 
 
f7ba937
 
 
 
 
 
 
 
 
 
 
f994803
 
f7ba937
f994803
f7ba937
 
 
f994803
 
 
 
 
 
 
 
 
 
 
f7ba937
 
f994803
 
 
 
 
 
 
 
 
 
 
 
f7ba937
f994803
f7ba937
f994803
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f7ba937
f994803
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import asyncio
import threading
import socket
from http.server import HTTPServer, BaseHTTPRequestHandler

import pandas as pd
import requests
from asyncua import Server, ua

# =========================
# CONFIGURATION
# =========================
BIND_IP = "::"            # IPv6 wildcard
OPCUA_PORT = 4840
HTTP_PORT = 7860
CSV_FILE = "data.csv"
ROW_INTERVAL = 2  # seconds

# =========================
# PUBLIC IP DETECTION (IPv6)
# =========================
def get_public_ip():
    try:
        # This returns IPv6 if available
        return requests.get("https://api64.ipify.org", timeout=5).text.strip()
    except Exception:
        return "::1"

PUBLIC_IP = get_public_ip()

# Wrap IPv6 in brackets for URL usage
def format_host(ip):
    if ":" in ip:
        return f"[{ip}]"
    return ip

FORMATTED_BIND = format_host(BIND_IP)
FORMATTED_PUBLIC = format_host(PUBLIC_IP)

ENDPOINT = f"opc.tcp://{FORMATTED_BIND}:{OPCUA_PORT}/csv-opcua-server/"
PUBLIC_ENDPOINT = f"opc.tcp://{FORMATTED_PUBLIC}:{OPCUA_PORT}/csv-opcua-server/"

# =========================
# IPV6 HTTP SERVER
# =========================
class IPv6HTTPServer(HTTPServer):
    address_family = socket.AF_INET6

class HealthHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()
        self.wfile.write(b"OK - Server is reachable via browser\n")

    def log_message(self, format, *args):
        return

def start_http_server():
    httpd = IPv6HTTPServer((BIND_IP, HTTP_PORT), HealthHandler)
    print(f"HTTP server running on http://{FORMATTED_PUBLIC}:{HTTP_PORT}")
    httpd.serve_forever()

# =========================
# MAIN ASYNC OPC UA SERVER
# =========================
async def main():
    df = pd.read_csv(CSV_FILE)
    if df.empty:
        raise ValueError("CSV file is empty")

    server = Server()
    await server.init()

    server.set_endpoint(ENDPOINT)
    server.set_server_name("IPv6 CSV OPC UA Async Server")

    uri = "http://example.org/public-csv-opcua"
    idx = await server.register_namespace(uri)

    objects = server.nodes.objects
    csv_obj = await objects.add_object(idx, "CSV_Data")

    variables = {}
    for col in df.columns:
        var = await csv_obj.add_variable(
            idx,
            col,
            float(df[col].iloc[0]),
            ua.VariantType.Double,
        )
        await var.set_writable()
        variables[col] = var

    print("====================================")
    print(" OPC UA SERVER RUNNING (IPv6)")
    print(f" Internal bind : {ENDPOINT}")
    print(f" Public access : {PUBLIC_ENDPOINT}")
    print(f" Publishing 1 row every {ROW_INTERVAL} seconds")
    print("====================================")

    row_index = 0
    row_count = len(df)

    async with server:
        while True:
            row = df.iloc[row_index]
            print(f"Publishing row {row_index + 1}/{row_count}")

            for col, var in variables.items():
                value = float(row[col])
                await var.write_value(value)
                print(f"  {col} = {value}")

            row_index = (row_index + 1) % row_count
            await asyncio.sleep(ROW_INTERVAL)

# =========================
# START EVERYTHING
# =========================
if __name__ == "__main__":
    threading.Thread(target=start_http_server, daemon=True).start()
    asyncio.run(main())