CoAP μ•Œμ•„λ³΄κΈ° - slog

ν•™κ΅μ—μ„œ ν•™μƒμ—κ²Œ IoT λ„€νŠΈμ›Œν¬ ν”„λ‘œκ·Έλž˜λ°μ„ κ°€λ₯΄μΉ˜κ³  μžˆλŠ”λ°, λ‹€μŒ μ£Ό κ°•μ˜μ—μ„œ CoAPλ₯Ό κ°€λ₯΄μ³μ•Ό ν•©λ‹ˆλ‹€.
IoTλ‚˜ M2M κ΄€λ ¨ ν˜„μ—…μ— μžˆμ§€ μ•Šκ³ μ„œλŠ” CoAPλ₯Ό μ ‘ν•˜κΈ°λž€ 쉽지 μ•ŠμŠ΅λ‹ˆλ‹€. μ € λ˜ν•œ CoAP κ΄€λ ¨ κ²½ν—˜μ€ μ—†μŠ΅λ‹ˆλ‹€. 이둠적으둜 κ°€λ₯΄μΉ  μˆ˜μ€€μ˜ ν•™μŠ΅μ€ 금방 κ°€λŠ₯ν–ˆλŠ”λ°, λ˜ν•œ ν”„λ‘œκ·Έλž˜λ¨Έμ΄λ―€λ‘œ CoAPλ₯Ό 직접 μ²΄ν—˜ν•˜κ³ μž ν•©λ‹ˆλ‹€.

λ¨Όμ € μ •μ˜λΆ€ν„° μ•Œμ•„λ΄…μ‹œλ‹€. μš°λ¦¬μ—κ²ŒλŠ” μœ„ν‚€λ°±κ³Όκ°€ μžˆμŠ΅λ‹ˆλ‹€.

CoAPλŠ” UPnPμ—μ„œ μ‚¬μš©λ˜λŠ” HTTPU(HTTP의 UDP 버젼)의 κΈ°λŠ₯을 IoTλ‚˜ M2M ν™˜κ²½μ—μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ νŠΉν™”ν•˜μ—¬ λ§Œλ“  것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. UDP/IP κΈ°λ°˜μ΄κ³ μš”, μœ λ‹ˆμΊμŠ€νŠΈ 및 λ©€ν‹°μΊμŠ€νŠΈλ₯Ό ν™œμš©ν•œλ‹€κ³  ν•©λ‹ˆλ‹€. μ‰½κ²Œ HTTP 둜 λ³€ν™˜ν•  수 μžˆλ„λ‘ μ„€κ³„λ˜μ—ˆλ‹€κ³  ν•©λ‹ˆλ‹€.

μ’‹μ•„μš” 1

μ •μ„±νƒœλ‹˜μ˜ CoAP κ΄€λ ¨ κΈ€μž…λ‹ˆλ‹€.

https://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=0&detail=1&wid=12629

μ„±νƒœλ‹˜μ΄ 잘 λ§μ”€ν•˜μ‹  λŒ€λ‘œ, μ–΄μ§œν”Ό UDP/IP 기반의 ν”„λ‘œν† μ½œμ΄λ―€λ‘œ PCλ‚˜ λͺ¨λ°”일 ν™˜κ²½μ—μ„œ μ‚¬μš©ν•˜μ§€ λͺ»ν•˜λ¦¬λž€ 법도 μ—†μŠ΅λ‹ˆλ‹€.

μ’‹μ•„μš” 1

μ–Έμ–΄ 별 CoAP λΌμ΄λΈŒλŸ¬λ¦¬λ„ μ‰½κ²Œ μ ‘κ·Όν•  수 μžˆλ„λ‘ μœ„ν‚€λ°±κ³Όμ—μ„œ 잘 μ†Œκ°œν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

또,

https://coap.technology/

이곳을 톡해 CoAP에 κ΄€λ ¨λœ μœ μš©ν•œ μ§€λ£Œλ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

μ’‹μ•„μš” 1

Python 및 C# CoAP μ–Έμ–΄ κ΅¬ν˜„μ²΄ μž…λ‹ˆλ‹€.

μ’‹μ•„μš” 1

또,

https://coap.technology/tools.html

μ΄κ³³μ—μ„œ CoAPκ΄€λ ¨ λ‹€μ–‘ν•œ νˆ΄λ“€μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

μ’‹μ•„μš” 1

이제 CoAP .NET 라이브러리λ₯Ό μ΄μš©ν•΄μ„œ C#μ—μ„œ CoAPκ΄€λ ¨ 코딩을 ν•˜λ„λ‘ ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

ꡐ윑 ν™˜κ²½μ΄ WSL2 + Visual Studio Code μ΄λ―€λ‘œ λ¨Όμ € WSL2 ν„°λ―Έλ„λ‘œ Console ν”„λ‘œμ νŠΈλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

그리고 CoAP.NET νŒ¨ν‚€μ§€λ₯Ό λ“±λ‘ν•©λ‹ˆλ‹€.

dotnet add package CoAP

그리고 Visual Studio Codeλ₯Ό μ‹€ν–‰ ν•©λ‹ˆλ‹€.

code .

ν„°λ―Έλ„μ—μ„œ CoAP νŒ¨ν‚€μ§€κ°€ 등둝 ν›„ 잘 μ‹€ν–‰λ˜λŠ”μ§€λ₯Ό ν™•μΈν•©λ‹ˆλ‹€.

dotent run
/home/dimohy/study/l5/l5.csproj : warning NU1701: Package 'CoAP 1.1.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework 'net6.0'. This package may not be fully compatible with your project.
/home/dimohy/study/l5/l5.csproj : warning NU1701: Package 'CoAP 1.1.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework 'net6.0'. This package may not be fully compatible with your project.

흠, .NET Framework 용 νŒ¨ν‚€μ§€κ°€ μ„€μΉ˜κ°€ 된 λ“― ν•˜κ΅°μš”. CoAP.NET.Coreλ₯Ό μ„€μΉ˜ν•΄μ•Όλ§Œ ν–ˆμ—ˆμŠ΅λ‹ˆλ‹€.

dotnet remove package CoAP

ν•œ ν›„,

dotnet add package CoAP.NET.Core

λ₯Ό λ‹€μ‹œ ν•΄μ£Όκ³  dotnet run ν•΄λ΄…λ‹ˆλ‹€.

dimohy@dimohy-nb:~/study/l5$ dotnet run
Hello, World!

잘 λ“±λ‘λκ΅°μš”! ^^;;;

μ’‹μ•„μš” 1

λ¨Όμ € GitHub에 μžˆλŠ” μ†ŒμŠ€μ½”λ“œλ₯Ό 따라 ν•΄λ΄…μ‹œλ‹€. 접속을 ν•΄μ•Ό ν•˜λ―€λ‘œ μ„œλ²„ λ¨Όμ € λ§Œλ“€μ–΄ λ΄…λ‹ˆλ‹€.

using CoAP.Server;
using CoAP.Server.Resources;


var s = new CoapServer();
s.Add(new HelloWorldResource());
s.Start();

Console.WriteLine("Press any key to exit...");
Console.ReadLine();

class HelloWorldResource : Resource
{
    public HelloWorldResource() : base("hello-world")
    {
        Attributes.Title = "Get a friendly greeting!";
    }

    protected override void DoGet(CoapExchange exchange)
    {
        exchange.Respond("Hello World from CoAP.NET!");
    }
}
$ dotnet run
Press any key to exit...

였 잘 μ‹€ν–‰λ©λ‹ˆλ‹€. CoAP.NETμ—μ„œ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯은 λ‹€μ–‘ν•˜κ² μ§€λ§Œ, 일단 HelloWorldResourceλΌλŠ” μžμ›μ„ μƒμ„±ν–ˆκ³ , μžμ›μ„ β€œhello-world” λΌλŠ” μ΄λ¦„μœΌλ‘œ λ“±λ‘ν–ˆμŠ΅λ‹ˆλ‹€. 이제 ν΄λΌμ΄μ–ΈνŠΈ 코딩을 ν•΄μ„œ 톡신 ν…ŒμŠ€νŠΈλ₯Ό ν•΄λ΄…μ‹œλ‹€.

ν΄λΌμ΄μ–ΈνŠΈλ₯Ό λ³„λ„μ˜ ν”„λ‘œμ νŠΈλ‘œ λ§Œλ“œλŠ” 것은 μ’€ λ²ˆκ±°λ‘œμš°λ―€λ‘œ λͺ…령쀄 인자둜 λΆ„κΈ°ν•˜λ„λ‘ ν•©μ‹œλ‹€.

using CoAP;
using CoAP.Server;
using CoAP.Server.Resources;


if (args.Length == 0 || args[0] != "S" && args[0] != "C")
{
    Console.WriteLine(@"No command line arguments.
S : Server
C : Client
");
    return;
}

var cmd = args[0];

if (cmd == "S")
{
    var s = new CoapServer();
    s.Add(new HelloWorldResource());
    s.Start();

    Console.WriteLine("Press any key to exit...");
    Console.ReadLine();
}
else if (cmd == "C")
{
    var req = new Request(Method.GET);
    req.URI = new("coap://[::1]/hello-world");
    req.Send();

    var res = req.WaitForResponse();
    Console.WriteLine($"Response : {res.ResponseText}");
}

class HelloWorldResource : Resource
{
    public HelloWorldResource() : base("hello-world")
    {
        Attributes.Title = "Get a friendly greeting!";
    }

    protected override void DoGet(CoapExchange exchange)
    {
        exchange.Respond("Hello World from CoAP.NET!");
    }
}

dotnet buildλ₯Ό ν•œλ²ˆ ν•΄μ£Όκ³ , μ„œλ²„λŠ” dotnet run S둜 λ¨Όμ € λ„μš΄ ν›„ dotnet run C둜 ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ‹€ν–‰ν•΄λ΄…λ‹ˆλ‹€.

$ dotnet run C
Response : Hello World from CoAP.NET!

잘 μ‹€ν–‰λ˜λŠ”κ΅°μš”!

μ’‹μ•„μš” 1

CoAPλŠ” CoAP Observe라고 ν•΄μ„œ μ£Όκ±°λ‹ˆ λ°›κ±°λ‹ˆ ν•˜μ§€ μ•Šκ³  ν•œλ²ˆ ꡬ독 μ‹ μ²­ ν›„, 이후 주기적으둜 정보λ₯Ό μˆ˜μ‹ ν•˜λŠ” κΈ°λŠ₯도 μžˆμŠ΅λ‹ˆλ‹€.

Observing Resources in CoAP (ietf.org)

Microsoft Word - CPL-TR-17-01-CoAP-Observe (knu.ac.kr)

μ’‹μ•„μš” 1

이제 PythonμœΌλ‘œλ„ ν•΄λ΄…μ‹œλ‹€. Pythonμ—μ„œλŠ” CoAPthon으둜 ν•™μŠ΅μ„ μ§„ν–‰ν•˜λ € ν•©λ‹ˆλ‹€.

λ¨Όμ €, CoAPthon을 pipλ₯Ό 톡해 μ„€μΉ˜ν•©λ‹ˆλ‹€.

sudo pip3 install CoAPthon3

이후 code l5.py둜 Visual Studio Codeμ—μ„œ νŒŒμ΄μ„  μ½”λ“œλ₯Ό μ—° ν›„,

from coapthon.server.coap import CoAP

print('!')

λ₯Ό 톡해 ν•΄λ‹Ή νŒ¨ν‚€μ§€κ°€ 잘 포함 λ˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€. 문제 없이 포함 λ˜μ—ˆκ΅°μš”. 이후 κΉƒν—ˆλΈŒμ— λ‚˜μ™€μžˆλŠ” 예제 μ°Έκ³  μ‚Όμ•„ μ½”λ”©ν•©λ‹ˆλ‹€.

from coapthon.server.coap import CoAP
from coapthon.resources.resource import Resource

class HelloWorldResource(Resource):
    def __init__(self, name="hello-world", coap_server=None):
        super(HelloWorldResource, self).__init__(name, coap_server, visible=True, observable=True, allow_children=True)

        self.payload = "Get a friendly greeting!"
    
    def render_GET(self, request):
        self.payload = 'Hello World from CoAPthon!'
        return self

class CoAPServer(CoAP):
    def __init__(self, host, port):
        CoAP.__init__(self, (host, port))
        self.add_resource('hello-world/', HelloWorldResource())


def main():
    server = CoAPServer("0.0.0.0", 5683)
    try:
        server.listen(10)
    except KeyboardInterrupt:
        print("Server Shutdown")
        server.close()
        print("Exiting...")

if __name__ == '__main__':
    main()

이름을 l5-server.py라고 ν•˜κ³  μ‹€ν–‰ν•©λ‹ˆλ‹€.

python3.9 l5-server.py

λ‹€μŒμ€ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμž…λ‹ˆλ‹€. 이름을 l5-client.py둜 ν•©λ‹ˆλ‹€.

from coapthon.client.helperclient import HelperClient

host = "127.0.0.1"
port = 5683
path = "hello-world"

client = HelperClient(server=(host, port))
response = client.get(path)
print(response.payload)
client.stop()

python3.9 l5-client.py둜 μ‹€ν–‰ν•΄ λ΄…λ‹ˆλ‹€.

$ python3.9 l5-client.py
Hello World from CoAPthon!

μž˜λ©λ‹ˆλ‹€. 이제 C#으둜 λ§Œλ“  CoAP μ„œλ²„λ₯Ό λ„μ›Œ λ™μΌν•˜κ²Œ ν…ŒμŠ€νŠΈ ν•΄λ΄…λ‹ˆλ‹€.

$ python3.9 l5-client.py
Hello World from CoAP.NET!

ν”„λ‘œκ·Έλž˜λ° 언어와 상관없이 μƒν˜Έ CoAP둜 톡신이 잘 λ˜λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€!

μ’‹μ•„μš” 2