socket.sendto

Questions and discussion about The WiPy 1.0 board and CC3200 boards.
Target audience: Users with a WiPy 1.0 or CC3200 board.
nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

socket.sendto

Post by nui_de » Tue Nov 24, 2015 2:03 pm

Hi,

any Idea if UDP socket.sento method will be supported in future?

Thanks :mrgreen:

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: socket.sendto

Post by danicampora » Tue Nov 24, 2015 2:08 pm

Hi,

It's been supported since the first software release...

https://micropython.org/resources/docs/ ... ket.sendto

What makes you think it's not? Is there something not working for you?

Cheers,
Daniel

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: socket.sendto

Post by nui_de » Tue Nov 24, 2015 2:26 pm

Uh... I had the wrong documentation :oops: (ESP8266)

however, this code works with python34, but on wipy it throws the following error:
Traceback (most recent call last):
File "main.py", line 157, in <module>
File "ArtNet.py", line 66, in send_single_value
File "ArtNet.py", line 122, in __ArtDMX_broadcast
ValueError: invalid arguments
MicroPython v1.5-105-g50f5622 on 2015-11-09; WiPy with CC3200

This is line > self.s.sendto(result, (self.ip, self.port))

Code: Select all

import socket
import struct

import time


class ArtNet():
    packet_counter = 1
    dmxdata = [0, 0]

    def __init__(self, artnet_net, artnet_subnet, artnet_universe, ip, port):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.net = int(artnet_net)
        self.subnet = int(artnet_subnet)
        self.universe = int(artnet_universe)
        self.ip = ip
        self.port = int(port)
        print(self.port)
        #logger.debug("Init ArtNet Plugin done")

    def run(self):
        pass

    def stop(self):
        self.close()

    def __call__(self, var1=None, var2=None):
        if type(var1) == int and type(var2) == int:
            self.send_single_value(var1, var2)
        if type(var1) == int and type(var2) == list:
            self.send_frame_starting_at(var1, var2)
        if type(var1) == list and type(var2) == type(None):
            self.send_frame(var1)

    def send_single_value(self, adr, value):
        if adr < 1 or adr > 512:
            #logger.error("DMX address %s invalid" % adr)
            return

        while len(self.dmxdata) < adr:
            self.dmxdata.append(0)
        self.dmxdata[adr - 1] = value
        self.__ArtDMX_broadcast()

    def send_frame_starting_at(self, adr, values):
        if adr < 1 or adr > (512 - len(values) + 1):
            #logger.error("DMX address %s with length %s invalid" %
            #             (adr, len(values)))
            return

        while len(self.dmxdata) < (adr + len(values) - 1):
            self.dmxdata.append(0)
        cnt = 0
        for value in values:
            self.dmxdata[adr - 1 + cnt] = value
            cnt += 1
        self.__ArtDMX_broadcast()

    def send_frame(self, dmxframe):
        if len(dmxframe) < 2:
            #logger.error("Send at least 2 channels")
            return
        self.dmxdata = dmxframe
        self.__ArtDMX_broadcast()

    def __ArtDMX_broadcast(self):
#       logger.info("Incomming DMX: %s"%self.dmxdata)
        # New Array
        data = []
        # Fix ID 7byte + 0x00
        data.append("Art-Net\x00")
        # OpCode = OpOutput / OpDmx -> 0x5000, Low Byte first
        data.append(struct.pack('<H', 0x5000))
        # ProtVerHi and ProtVerLo -> Protocol Version 14, High Byte first
        data.append(struct.pack('>H', 14))
        # Order 1 to 255
        data.append(struct.pack('B', self.packet_counter))
        self.packet_counter += 1
        if self.packet_counter > 255:
            self.packet_counter = 1
        # Physical Input Port
        data.append(struct.pack('B', 0))
        # Artnet source address
        data.append(
            struct.pack('<H', self.net << 8 | self.subnet << 4 | self.universe))
        # Length of DMX Data, High Byte First
        data.append(struct.pack('>H', len(self.dmxdata)))
        # DMX Data
        for d in self.dmxdata:
            data.append(struct.pack('B', d))
        # convert from list to string
        result = bytes()
        for token in data:
            try:  # Handels all strings
                result = result + token.encode('utf-8', 'ignore')
            except:  # Handels all bytes
                result = result + token

        self.s.sendto(result, (self.ip, self.port))

    def close(self):
        self.s.close()


if __name__ == '__main__':
    artnet_subnet = 0
    artnet_net = 0
    artnet_universe = 0
    ip = 'localhost'
    port = 6454
    
    sh = ArtNet(artnet_net, artnet_subnet, artnet_universe, ip, port)

    value = 0
    while True:
        sh.send_single_value(12,value)
        time.sleep(1)
        if (value < 254):
            value +=1
        else:
            value = 0

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: socket.sendto

Post by danicampora » Tue Nov 24, 2015 2:51 pm

Umm, should work. Can you provide a smaller snippet that shows the error? Could it be the IP format? IPv6 is not supported by the way...

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: socket.sendto

Post by nui_de » Tue Nov 24, 2015 3:39 pm

Better?

Code: Select all

import socket
import struct

class ArtNet():
    packet_counter = 1
    dmxdata = [0, 0]

    def __init__(self, artnet_net, artnet_subnet, artnet_universe, ip, port):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.net = int(artnet_net)
        self.subnet = int(artnet_subnet)
        self.universe = int(artnet_universe)
        self.ip = ip
        self.port = int(port)
        print(self.port)

    def send_single_value(self, adr, value):
        if adr < 1 or adr > 512:
            return

        while len(self.dmxdata) < adr:
            self.dmxdata.append(0)
        self.dmxdata[adr - 1] = value
        self.__ArtDMX_broadcast()

    def __ArtDMX_broadcast(self):
        data = []
        data.append("Art-Net\x00")
        data.append(struct.pack('<H', 0x5000))
        data.append(struct.pack('>H', 14))
        data.append(struct.pack('B', self.packet_counter))
        self.packet_counter += 1
        if self.packet_counter > 255:
            self.packet_counter = 1
        data.append(struct.pack('B', 0))
        data.append(
            struct.pack('<H', self.net << 8 | self.subnet << 4 | self.universe))
        data.append(struct.pack('>H', len(self.dmxdata)))
        for d in self.dmxdata:
            data.append(struct.pack('B', d))
        result = bytes()
        for token in data:
            try:  # Handels all strings
                result = result + token.encode('utf-8', 'ignore')
            except:  # Handels all bytes
                result = result + token

        self.s.sendto(result, (self.ip, self.port))

    def close(self):
        self.s.close()


artnet_subnet = 0
artnet_net = 0
artnet_universe = 0
ip = 'localhost'
port = 6454
    
sh = ArtNet(artnet_net, artnet_subnet, artnet_universe, ip, port)
sh.send_single_value(12,100)

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: socket.sendto

Post by danicampora » Tue Nov 24, 2015 3:43 pm

The problem is with ip being 'localhost', this is not supported. Use: '127.0.0.1' instead...
Sorry that I didn't see it in the first snippet.

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: socket.sendto

Post by nui_de » Tue Nov 24, 2015 4:09 pm

Ahhrrrr!
Yep - that was easy, don't know why I did not realized it - thank you !

Works now, but I have another question...
Raw performance is ~130 packets/s (I was just curious)

I reduced to ~30 packets/s but however the light is not dimming smoothly.
With my artnet software on my PC i can see a history for the specific
channel - Time and Value.

Seems Wipy is not sending the packets consistent - is there any thing I can do
to improve this?

Many Thanks!

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: socket.sendto

Post by nui_de » Tue Nov 24, 2015 7:48 pm

Here is a litte illustration - The upper graphic shows artnet-packets received in the timeline,
thats how I want it to look.

The bottom graphic is the artnet-traffic when using the wipy (using soure above) Looks like its collecting (buffering) some
data before sending (height of Bars means amount of data).

Maybe sleep() is not accurate and I have to use a periodic timer.
Sorry to ask - I do not have enough background knowledge of the Hardware so I could understand why this happens.

Image

User avatar
danicampora
Posts: 342
Joined: Tue Sep 30, 2014 7:20 am
Contact:

Re: socket.sendto

Post by danicampora » Tue Nov 24, 2015 7:55 pm

Hi,

Can you show the code that you use to send periodically? On your first snippet, you do

Code: Select all

time.sleep(1)
, this will send something every 1 second. Try using time.sleep_ms instead.

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: socket.sendto

Post by nui_de » Tue Nov 24, 2015 9:19 pm

Hi,

yes I used "time.sleep_ms(30)"
With this I do get a framerate of ~20 Packets/s in my Artnet monitor.
But the problem is that five packets are send within some ms - followed by a longer break ~200ms.

Post Reply