diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml
index 694792dcd..0c80be9c7 100644
--- a/.github/workflows/check-certificates.yml
+++ b/.github/workflows/check-certificates.yml
@@ -6,6 +6,8 @@ on:
   push:
     paths:
       - ".github/workflows/check-certificates.ya?ml"
+    tags-ignore:
+      - '*'
   pull_request:
     paths:
       - ".github/workflows/check-certificates.ya?ml"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3b2a210d9..0e31abff3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -286,6 +286,11 @@ jobs:
             -k "${{ env.KEYCHAIN_PASSWORD }}" \
             "${{ env.KEYCHAIN }}"
 
+      - name: Install Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: ${{ env.GO_VERSION }}
+
       - name: Install gon for code signing
         uses: actions/checkout@v4
         with:
@@ -309,7 +314,7 @@ jobs:
           bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}"
 
           sign {
-            application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)"
+            application_identity = "Massimo Banzi Apple Key"
             deep = true
           }
 
@@ -577,7 +582,7 @@ jobs:
           bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}-installer"
 
           sign {
-            application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)"
+            application_identity = "Massimo Banzi Apple Key"
           }
 
           # Ask Gon for zip output to force notarization process to take place.
diff --git a/bufferflow.go b/bufferflow.go
deleted file mode 100644
index a9fef8e51..000000000
--- a/bufferflow.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-package main
-
-// Bufferflow interface
-type Bufferflow interface {
-	Init()
-	OnIncomingData(data string) // implement this method
-	Close()                     // implement this method
-}
diff --git a/bufferflow_default.go b/bufferflow_default.go
deleted file mode 100644
index 959737d54..000000000
--- a/bufferflow_default.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"encoding/json"
-
-	log "github.com/sirupsen/logrus"
-)
-
-// BufferflowDefault is the default bufferflow, whick means no buffering
-type BufferflowDefault struct {
-	port   string
-	output chan<- []byte
-	input  chan string
-	done   chan bool
-}
-
-// NewBufferflowDefault create a new default bufferflow
-func NewBufferflowDefault(port string, output chan<- []byte) *BufferflowDefault {
-	return &BufferflowDefault{
-		port:   port,
-		output: output,
-		input:  make(chan string),
-		done:   make(chan bool),
-	}
-}
-
-// Init will initialize the bufferflow
-func (b *BufferflowDefault) Init() {
-	log.Println("Initting default buffer flow (which means no buffering)")
-	go b.consumeInput()
-}
-
-func (b *BufferflowDefault) consumeInput() {
-Loop:
-	for {
-		select {
-		case data := <-b.input:
-			m := SpPortMessage{b.port, data}
-			message, _ := json.Marshal(m)
-			b.output <- message
-		case <-b.done:
-			break Loop //this is required, a simple break statement would only exit the innermost switch statement
-		}
-	}
-	close(b.input) // close the input channel at the end of the computation
-}
-
-// OnIncomingData will forward the data
-func (b *BufferflowDefault) OnIncomingData(data string) {
-	b.input <- data
-}
-
-// Close will close the bufferflow
-func (b *BufferflowDefault) Close() {
-	b.done <- true
-	close(b.done)
-}
diff --git a/bufferflow_timed.go b/bufferflow_timed.go
index 36aaf08bf..6c5fab04a 100644
--- a/bufferflow_timed.go
+++ b/bufferflow_timed.go
@@ -33,8 +33,8 @@ type BufferflowTimed struct {
 	bufferedOutput string
 }
 
-// NewBufferflowTimed will create a new timed bufferflow
-func NewBufferflowTimed(port string, output chan<- []byte) *BufferflowTimed {
+// NewBufferFlowTimed will create a new timed bufferflow
+func NewBufferFlowTimed(port string, output chan<- []byte) *BufferflowTimed {
 	return &BufferflowTimed{
 		port:           port,
 		output:         output,
@@ -48,7 +48,7 @@ func NewBufferflowTimed(port string, output chan<- []byte) *BufferflowTimed {
 
 // Init will initialize the bufferflow
 func (b *BufferflowTimed) Init() {
-	log.Println("Initting timed buffer flow (output once every 16ms)")
+	log.Println("Start consuming from serial port (output once every 16ms)")
 	go b.consumeInput()
 }
 
diff --git a/bufferflow_timedraw.go b/bufferflow_timedraw.go
deleted file mode 100644
index 08b34cab6..000000000
--- a/bufferflow_timedraw.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"encoding/json"
-	"time"
-
-	log "github.com/sirupsen/logrus"
-)
-
-// BufferflowTimedRaw sends raw data once every 16ms
-type BufferflowTimedRaw struct {
-	port              string
-	output            chan<- []byte
-	input             chan string
-	done              chan bool
-	ticker            *time.Ticker
-	bufferedOutputRaw []byte
-	sPortRaw          string
-}
-
-// NewBufferflowTimedRaw will create a new raw bufferflow
-func NewBufferflowTimedRaw(port string, output chan<- []byte) *BufferflowTimedRaw {
-	return &BufferflowTimedRaw{
-		port:              port,
-		output:            output,
-		input:             make(chan string),
-		done:              make(chan bool),
-		ticker:            time.NewTicker(16 * time.Millisecond),
-		bufferedOutputRaw: nil,
-		sPortRaw:          "",
-	}
-}
-
-// Init will initialize the bufferflow
-func (b *BufferflowTimedRaw) Init() {
-	log.Println("Initting timed buffer raw flow (output once every 16ms)")
-	go b.consumeInput()
-}
-
-func (b *BufferflowTimedRaw) consumeInput() {
-Loop:
-	for {
-		select {
-		case data := <-b.input: // use the buffer and append data to it
-			b.bufferedOutputRaw = append(b.bufferedOutputRaw, []byte(data)...)
-			b.sPortRaw = b.port
-		case <-b.ticker.C: // after 16ms send the buffered output message
-			if b.bufferedOutputRaw != nil {
-				m := SpPortMessageRaw{b.sPortRaw, b.bufferedOutputRaw}
-				buf, _ := json.Marshal(m)
-				// since bufferedOutputRaw is a []byte is base64-encoded by json.Marshal() function automatically
-				b.output <- buf
-				// reset the buffer and the port
-				b.bufferedOutputRaw = nil
-				b.sPortRaw = ""
-			}
-		case <-b.done:
-			break Loop //this is required, a simple break statement would only exit the innermost switch statement
-		}
-	}
-	close(b.input)
-}
-
-// OnIncomingData will forward the data
-func (b *BufferflowTimedRaw) OnIncomingData(data string) {
-	b.input <- data
-}
-
-// Close will close the bufferflow
-func (b *BufferflowTimedRaw) Close() {
-	b.ticker.Stop()
-	b.done <- true
-	close(b.done)
-}
diff --git a/config/config.go b/config/config.go
index 69d29eeee..50978eb82 100644
--- a/config/config.go
+++ b/config/config.go
@@ -142,3 +142,41 @@ func SetInstallCertsIni(filename string, value string) error {
 	}
 	return nil
 }
+
+func GetConfigPath() *paths.Path {
+	// Let's handle the config
+	configDir := GetDefaultConfigDir()
+	var configPath *paths.Path
+
+	// see if the env var is defined, if it is take the config from there, this will override the default path
+	if envConfig := os.Getenv("ARDUINO_CREATE_AGENT_CONFIG"); envConfig != "" {
+		configPath = paths.New(envConfig)
+		if configPath.NotExist() {
+			log.Panicf("config from env var %s does not exists", envConfig)
+		}
+		log.Infof("using config from env variable: %s", configPath)
+	} else if defaultConfigPath := configDir.Join("config.ini"); defaultConfigPath.Exist() {
+		// by default take the config from the ~/.arduino-create/config.ini file
+		configPath = defaultConfigPath
+		log.Infof("using config from default: %s", configPath)
+	} else {
+		// Fall back to the old config.ini location
+		src, _ := os.Executable()
+		oldConfigPath := paths.New(src).Parent().Join("config.ini")
+		if oldConfigPath.Exist() {
+			err := oldConfigPath.CopyTo(defaultConfigPath)
+			if err != nil {
+				log.Errorf("cannot copy old %s, to %s, generating new config", oldConfigPath, configPath)
+			} else {
+				configPath = defaultConfigPath
+				log.Infof("copied old %s, to %s", oldConfigPath, configPath)
+			}
+		}
+	}
+	if configPath == nil {
+		configPath = GenerateConfig(configDir)
+	}
+
+	return configPath
+
+}
diff --git a/config/config_test.go b/config/config_test.go
new file mode 100644
index 000000000..76e6988c0
--- /dev/null
+++ b/config/config_test.go
@@ -0,0 +1,61 @@
+package config
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/arduino/go-paths-helper"
+	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetConfigPath(t *testing.T) {
+	t.Run("read config.ini from ARDUINO_CREATE_AGENT_CONFIG", func(t *testing.T) {
+		os.Setenv("ARDUINO_CREATE_AGENT_CONFIG", "./testdata/fromenv/config.ini")
+		defer os.Unsetenv("ARDUINO_CREATE_AGENT_CONFIG")
+		configPath := GetConfigPath()
+		assert.Equal(t, "./testdata/fromenv/config.ini", configPath.String())
+	})
+
+	t.Run("panic if config.ini does not exist", func(t *testing.T) {
+		os.Setenv("ARDUINO_CREATE_AGENT_CONFIG", "./testdata/nonexistent_config.ini")
+		defer os.Unsetenv("ARDUINO_CREATE_AGENT_CONFIG")
+
+		defer func() {
+			if r := recover(); r != nil {
+				entry, ok := r.(*logrus.Entry)
+				if !ok {
+					t.Errorf("Expected panic of type *logrus.Entry but got %T", r)
+				} else {
+					assert.Equal(t, "config from env var ./testdata/nonexistent_config.ini does not exists", entry.Message)
+				}
+			} else {
+				t.Errorf("Expected panic but did not get one")
+			}
+		}()
+
+		GetConfigPath()
+	})
+
+	t.Run("read config.ini from $HOME", func(t *testing.T) {
+		os.Setenv("HOME", "./testdata/home")
+		defer os.Unsetenv("HOME")
+		configPath := GetConfigPath()
+		assert.Equal(t, "testdata/home/.config/ArduinoCreateAgent/config.ini", configPath.String())
+	})
+
+	t.Run("fallback old : read config.ini where the binary is launched", func(t *testing.T) {
+		src, _ := os.Executable()
+		paths.New(src).Parent().Join("config.ini").Create() // create a config.ini in the same directory as the binary
+		// The fallback path is the directory where the binary is launched
+		fmt.Println(src)
+		os.Setenv("HOME", "./testdata/noconfig") // force to not have a config in the home directory
+		defer os.Unsetenv("HOME")
+
+		// expect it creates a config.ini in the same directory as the binary
+		configPath := GetConfigPath()
+		assert.Equal(t, "testdata/home/.config/ArduinoCreateAgent/config.ini", configPath.String())
+	})
+
+}
diff --git a/config/testdata/fromenv/config.ini b/config/testdata/fromenv/config.ini
new file mode 100644
index 000000000..5b31315b9
--- /dev/null
+++ b/config/testdata/fromenv/config.ini
@@ -0,0 +1,8 @@
+gc = std
+hostname = unknown-hostname
+regex = usb|acm|com
+v = true
+appName = CreateAgent/Stable
+updateUrl = https://downloads.arduino.cc/
+origins = https://local.arduino.cc:8000, https://local.arduino.cc:8001, https://create-dev.arduino.cc, https://*.sparklyunicorn.cc, https://*.iot-cloud-arduino-cc.pages.dev, https://cloud.oniudra.cc, https://app.oniudra.cc,https://*.iot-cloud-arduino-cc.pages.dev
+crashreport = false
diff --git a/config/testdata/home/.config/ArduinoCreateAgent/config.ini b/config/testdata/home/.config/ArduinoCreateAgent/config.ini
new file mode 100644
index 000000000..92f231faf
--- /dev/null
+++ b/config/testdata/home/.config/ArduinoCreateAgent/config.ini
@@ -0,0 +1,8 @@
+gc = std
+hostname = unknown-hostname
+regex = usb|acm|com
+v = true
+appName = config-from-home-dir
+updateUrl = https://downloads.arduino.cc/
+origins = https://local.arduino.cc:8000, https://local.arduino.cc:8001, https://*.iot-cloud-arduino-cc.pages.dev
+crashreport = false
diff --git a/config/testdata/noconfig/.config/ArduinoCreateAgent/config.ini b/config/testdata/noconfig/.config/ArduinoCreateAgent/config.ini
new file mode 100644
index 000000000..f63377db5
--- /dev/null
+++ b/config/testdata/noconfig/.config/ArduinoCreateAgent/config.ini
@@ -0,0 +1,10 @@
+gc = std  # Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)
+hostname = unknown-hostname  # Override the hostname we get from the OS
+regex = usb|acm|com  # Regular expression to filter serial port list
+v = true  # show debug logging
+appName = CreateAgent/Stable
+updateUrl = https://downloads.arduino.cc/
+origins = https://local.arduino.cc:8000
+#httpProxy = http://your.proxy:port # Proxy server for HTTP requests
+crashreport = false # enable crashreport logging
+autostartMacOS = true # the Arduino Create Agent is able to start automatically after login on macOS (launchd agent)
\ No newline at end of file
diff --git a/hub.go b/hub.go
index a162dd01a..81a169121 100755
--- a/hub.go
+++ b/hub.go
@@ -58,7 +58,7 @@ var h = hub{
 const commands = `{
   "Commands": [
     "list",
-    "open <portName> <baud> [bufferAlgorithm: ({default}, timed, timedraw)]",
+    "open <portName> <baud>",
     "(send, sendnobuf, sendraw) <portName> <cmd>",
     "close <portName>",
     "restart",
@@ -146,15 +146,13 @@ func checkCmd(m []byte) {
 			go spErr("Problem converting baud rate " + args[2])
 			return
 		}
-		// pass in buffer type now as string. if user does not
-		// ask for a buffer type pass in empty string
-		bufferAlgorithm := "default" // use the default buffer if none is specified
+
+		// Ignore extra "buffer type" param for backward compatibility
 		if len(args) > 3 {
-			// cool. we got a buffer type request
-			buftype := strings.Replace(args[3], "\n", "", -1)
-			bufferAlgorithm = buftype
+			log.Warn(fmt.Sprintf("Unexpected arguments for the open command. Ignored arguments: '%s'.", args[3:]))
 		}
-		go spHandlerOpen(args[1], baud, bufferAlgorithm)
+
+		go spHandlerOpen(args[1], baud)
 
 	} else if strings.HasPrefix(sl, "close") {
 
diff --git a/main.go b/main.go
index 1ca857b02..a83d7f4c5 100755
--- a/main.go
+++ b/main.go
@@ -22,6 +22,7 @@ import (
 	_ "embed"
 	"encoding/json"
 	"flag"
+	"fmt"
 	"html/template"
 	"io"
 	"os"
@@ -188,38 +189,9 @@ func loop() {
 		h.broadcastSys <- mapB
 	}
 
-	// Let's handle the config
-	configDir := config.GetDefaultConfigDir()
-	var configPath *paths.Path
+	configPath := config.GetConfigPath()
 
-	// see if the env var is defined, if it is take the config from there, this will override the default path
-	if envConfig := os.Getenv("ARDUINO_CREATE_AGENT_CONFIG"); envConfig != "" {
-		configPath = paths.New(envConfig)
-		if configPath.NotExist() {
-			log.Panicf("config from env var %s does not exists", envConfig)
-		}
-		log.Infof("using config from env variable: %s", configPath)
-	} else if defaultConfigPath := configDir.Join("config.ini"); defaultConfigPath.Exist() {
-		// by default take the config from the ~/.arduino-create/config.ini file
-		configPath = defaultConfigPath
-		log.Infof("using config from default: %s", configPath)
-	} else {
-		// Fall back to the old config.ini location
-		src, _ := os.Executable()
-		oldConfigPath := paths.New(src).Parent().Join("config.ini")
-		if oldConfigPath.Exist() {
-			err := oldConfigPath.CopyTo(defaultConfigPath)
-			if err != nil {
-				log.Errorf("cannot copy old %s, to %s, generating new config", oldConfigPath, configPath)
-			} else {
-				configPath = defaultConfigPath
-				log.Infof("copied old %s, to %s", oldConfigPath, configPath)
-			}
-		}
-	}
-	if configPath == nil {
-		configPath = config.GenerateConfig(configDir)
-	}
+	fmt.Println("configPath: ", configPath)
 
 	// if the default browser is Safari, prompt the user to install HTTPS certificates
 	// and eventually install them
diff --git a/serial.go b/serial.go
index 64e5b8f7f..f58414571 100755
--- a/serial.go
+++ b/serial.go
@@ -67,7 +67,7 @@ var sh = serialhub{
 func (sh *serialhub) Register(port *serport) {
 	sh.mu.Lock()
 	//log.Print("Registering a port: ", p.portConf.Name)
-	h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Got register/open on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + ",\"BufferType\":\"" + port.BufferType + "\"}")
+	h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Got register/open on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + "}")
 	sh.ports[port] = true
 	sh.mu.Unlock()
 }
diff --git a/serialport.go b/serialport.go
index 0d386bbfc..9a06c7f9c 100755
--- a/serialport.go
+++ b/serialport.go
@@ -22,7 +22,6 @@ import (
 	"strconv"
 	"sync/atomic"
 	"time"
-	"unicode/utf8"
 
 	log "github.com/sirupsen/logrus"
 	serial "go.bug.st/serial"
@@ -57,10 +56,7 @@ type serport struct {
 	// channel containing raw base64 encoded binary data (outbound messages)
 	sendRaw chan string
 
-	// Do we have an extra channel/thread to watch our buffer?
-	BufferType string
-	//bufferwatcher *BufferflowDummypause
-	bufferwatcher Bufferflow
+	bufferFlow *BufferflowTimed
 }
 
 // SpPortMessage is the serial port message
@@ -75,15 +71,13 @@ type SpPortMessageRaw struct {
 	D []byte // the data, i.e. G0 X0 Y0
 }
 
-func (p *serport) reader(buftype string) {
+func (p *serport) reader() {
 
 	timeCheckOpen := time.Now()
-	var bufferedCh bytes.Buffer
 
 	serialBuffer := make([]byte, 1024)
 	for {
 		n, err := p.portIo.Read(serialBuffer)
-		bufferPart := serialBuffer[:n]
 
 		//if we detect that port is closing, break out of this for{} loop.
 		if p.isClosing.Load() {
@@ -96,39 +90,8 @@ func (p *serport) reader(buftype string) {
 		// read can return legitimate bytes as well as an error
 		// so process the n bytes red, if n > 0
 		if n > 0 && err == nil {
-
-			log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(bufferPart[:n]))
-
-			data := ""
-			switch buftype {
-			case "timedraw", "timed":
-				data = string(bufferPart[:n])
-				// give the data to our bufferflow so it can do it's work
-				// to read/translate the data to see if it wants to block
-				// writes to the serialport. each bufferflow type will decide
-				// this on its own based on its logic
-				p.bufferwatcher.OnIncomingData(data)
-			case "default": // the bufferbuftype is actually called default 🤷‍♂️
-				// save the left out bytes for the next iteration due to UTF-8 encoding
-				bufferPart = append(bufferedCh.Bytes(), bufferPart[:n]...)
-				n += len(bufferedCh.Bytes())
-				bufferedCh.Reset()
-				for i, w := 0, 0; i < n; i += w {
-					runeValue, width := utf8.DecodeRune(bufferPart[i:n]) // try to decode the first i bytes in the buffer (UTF8 runes do not have a fixed length)
-					if runeValue == utf8.RuneError {
-						bufferedCh.Write(bufferPart[i:n])
-						break
-					}
-					if i == n {
-						bufferedCh.Reset()
-					}
-					data += string(runeValue)
-					w = width
-				}
-				p.bufferwatcher.OnIncomingData(data)
-			default:
-				log.Panicf("unknown buffer type %s", buftype)
-			}
+			log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(serialBuffer[:n]))
+			p.bufferFlow.OnIncomingData(string(serialBuffer[:n]))
 		}
 
 		// double check that we got characters in the buffer
@@ -273,7 +236,7 @@ func (p *serport) writerRaw() {
 	h.broadcastSys <- []byte(msgstr)
 }
 
-func spHandlerOpen(portname string, baud int, buftype string) {
+func spHandlerOpen(portname string, baud int) {
 
 	log.Print("Inside spHandler")
 
@@ -312,23 +275,10 @@ func spHandlerOpen(portname string, baud int, buftype string) {
 		portConf:     conf,
 		portIo:       sp,
 		portName:     portname,
-		BufferType:   buftype}
-
-	var bw Bufferflow
-
-	switch buftype {
-	case "timed":
-		bw = NewBufferflowTimed(portname, h.broadcastSys)
-	case "timedraw":
-		bw = NewBufferflowTimedRaw(portname, h.broadcastSys)
-	case "default":
-		bw = NewBufferflowDefault(portname, h.broadcastSys)
-	default:
-		log.Panicf("unknown buffer type: %s", buftype)
 	}
 
-	bw.Init()
-	p.bufferwatcher = bw
+	p.bufferFlow = NewBufferFlowTimed(portname, h.broadcastSys)
+	p.bufferFlow.Init()
 
 	sh.Register(p)
 	defer sh.Unregister(p)
@@ -343,7 +293,7 @@ func spHandlerOpen(portname string, baud int, buftype string) {
 	// this is thread to send to serial port but with base64 decoding
 	go p.writerRaw()
 
-	p.reader(buftype)
+	p.reader()
 
 	serialPorts.List()
 }
@@ -351,7 +301,7 @@ func spHandlerOpen(portname string, baud int, buftype string) {
 func (p *serport) Close() {
 	p.isClosing.Store(true)
 
-	p.bufferwatcher.Close()
+	p.bufferFlow.Close()
 	p.portIo.Close()
 	serialPorts.MarkPortAsClosed(p.portName)
 	serialPorts.List()
diff --git a/tests/test_ws.py b/tests/test_ws.py
index b8004649d..2f3ee9fa5 100644
--- a/tests/test_ws.py
+++ b/tests/test_ws.py
@@ -49,77 +49,28 @@ def test_list(socketio, message):
     running_on_ci(),
     reason="VMs have no serial ports",
 )
-def test_open_serial_default(socketio, serial_port, baudrate, message):
-    general_open_serial(socketio, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_open_serial_timed(socketio, serial_port, baudrate, message):
-    general_open_serial(socketio, serial_port, baudrate, message, "timed")
-
-
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_open_serial_timedraw(socketio, serial_port, baudrate, message):
-    general_open_serial(socketio, serial_port, baudrate, message, "timedraw")
-
+def test_open_serial(socketio, serial_port, baudrate, message):
+    general_open_serial(socketio, serial_port, baudrate, message)
 
 # NOTE run the following tests with a board connected to the PC and with the sketch found in tests/testdata/SerialEcho.ino on it be sure to change serial_address in conftest.py
 @pytest.mark.skipif(
     running_on_ci(),
     reason="VMs have no serial ports",
 )
-def test_send_serial_default(socketio, close_port, serial_port, baudrate, message):
-    general_send_serial(socketio, close_port, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_send_serial_timed(socketio, close_port, serial_port, baudrate, message):
-    general_send_serial(socketio, close_port, serial_port, baudrate, message, "timed")
+def test_send_serial(socketio, close_port, serial_port, baudrate, message):
+    general_send_serial(socketio, close_port, serial_port, baudrate, message)
 
 
 @pytest.mark.skipif(
     running_on_ci(),
     reason="VMs have no serial ports",
 )
-def test_send_serial_timedraw(socketio, close_port, serial_port, baudrate, message):
-    general_send_serial(socketio, close_port, serial_port, baudrate, message, "timedraw")
+def test_send_emoji_serial(socketio, close_port, serial_port, baudrate, message):
+    general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message)
 
 
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_default(socketio, close_port, serial_port, baudrate, message):
-    general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_timed(socketio, close_port, serial_port, baudrate, message):
-    general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "timed")
-
-
-@pytest.mark.skipif(
-    running_on_ci(),
-    reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_timedraw(socketio, close_port, serial_port, baudrate, message):
-    general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "timedraw")
-
-
-def general_open_serial(socketio, serial_port, baudrate, message, buffertype):
-    open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_open_serial(socketio, serial_port, baudrate, message):
+    open_serial_port(socketio, serial_port, baudrate, message)
     # test the closing of the serial port, we are gonna use close_port for the other tests
     socketio.emit('command', 'close ' + serial_port)
     time.sleep(.2)
@@ -128,8 +79,8 @@ def general_open_serial(socketio, serial_port, baudrate, message, buffertype):
     assert any("\"IsOpen\": false," in i for i in message)
 
 
-def general_send_serial(socketio, close_port, serial_port, baudrate, message, buffertype):
-    open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_send_serial(socketio, close_port, serial_port, baudrate, message):
+    open_serial_port(socketio, serial_port, baudrate, message)
     # send the string "ciao" using the serial connection
     socketio.emit('command', 'send ' + serial_port + ' ciao')
     time.sleep(1)
@@ -137,33 +88,27 @@ def general_send_serial(socketio, close_port, serial_port, baudrate, message, bu
     # check if the send command has been registered
     assert any("send " + serial_port + " ciao" in i for i in message)
     #check if message has been sent back by the connected board
-    if buffertype == "timedraw":
-        output =  decode_output(extract_serial_data(message))
-    elif buffertype in ("default", "timed"):
-        output = extract_serial_data(message)
+    output = extract_serial_data(message)
     assert "ciao" in output
     # the serial connection is closed by close_port() fixture: even if in case of test failure
 
 
-def general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, buffertype):
-    open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message):
+    open_serial_port(socketio, serial_port, baudrate, message)
     # send a lot of emoji: they can be messed up
     socketio.emit('command', 'send ' + serial_port + ' /"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/"')
     time.sleep(1)
     print(message)
     # check if the send command has been registered
     assert any("send " + serial_port + " /\"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/\"" in i for i in message)
-    if buffertype == "timedraw":
-        output =  decode_output(extract_serial_data(message))
-    elif buffertype in ("default", "timed"):
-        output = extract_serial_data(message)
+    output = extract_serial_data(message)
     assert "/\"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/\"" in output
     # the serial connection is closed by close_port() fixture: even if in case of test failure
 
 
-def open_serial_port(socketio, serial_port, baudrate, message, buffertype):
-    #open a new serial connection with the specified buffertype
-    socketio.emit('command', 'open ' + serial_port + ' ' + baudrate + ' ' + buffertype)
+def open_serial_port(socketio, serial_port, baudrate, message):
+    #open a new serial connection
+    socketio.emit('command', 'open ' + serial_port + ' ' + baudrate)
     # give time to the message var to be filled
     time.sleep(.5)
     print(message)
@@ -176,7 +121,7 @@ def open_serial_port(socketio, serial_port, baudrate, message, buffertype):
     reason="VMs have no serial ports",
 )
 def test_sendraw_serial(socketio, close_port, serial_port, baudrate, message):
-    open_serial_port(socketio, serial_port, baudrate, message, "timedraw")
+    open_serial_port(socketio, serial_port, baudrate, message)
     #test with bytes
     integers = [1, 2, 3, 4, 5]
     bytes_array=bytearray(integers)
@@ -202,7 +147,7 @@ def extract_serial_data(msg):
             serial_data+=json.loads(i)["D"]
     print("serialdata:"+serial_data)
     return serial_data
-    
+
 def decode_output(raw_output):
     # print(raw_output)
     base64_bytes = raw_output.encode('ascii') #encode rawoutput message into a bytes-like object