JavaScript - strona się wysypuje po jakimś czasie.

0

Witam wszystkich,

Piszę z kolejnym problemem. Napisałem stronę która zapewnia komunikację pomiędzy sterownikiem, a PC. Strona ta odświeża wybrane wartości z urządzenia co dwie sekundy, następnie rysuje ich wykresy jak się zmieniają w czasie. Wszystko pięknie śmiga, tak jak chciałem. ALE! Problem w tym, że w pewnym momencie (mniej więcej po godzinie) wyrzuca mi komunikat z Windowsa "low memory", a po jakimś czasie strona generuje błędy i przeglądarka się sama wyłącza.

Da się coś z tym zrobić, drogie Panie i Panowie?

0

Da się

0

To dobrze :D
A mógłbym liczyć na pomoc z Twojej strony? :D Z resztą po raz kolejny, o ile dobrze kojarzę.

0

No ja myślę, że w linii 21 masz błąd. (liczę, że zrozumiałeś)

0

Jak najbardziej zrozumiałem. Myślałem, że jest jakaś funkcja kontrolująca takie cuda. :)
Był to mój pierwszy program więc proszę o wyrozumiałość.
Załączam plik.

0

Dzięki za wskazówki, zacznę przeglądać na pewno. :)

0

Wracam, przez chwilę mój problem nie był "nagły" jednak, zacząłem teraz o tym czytać i przyznam szczerze, ze się gubię.
Rozumiem, że mam te wycieki pamięci nie wiem tylko jak zlokwalizować miejsce w którym powstają i jak je powstrzymać, czyli najważniejszych rzeczy.

Podpowiecie mi jak mogę znaleźć miejsce ich występowania?

Edit:
Mam niemal pewność, że za wyciek odpowiada: getJSON, przykładowo:

$.getJSON("I_Pressures.htm", function(data){
					
				tab_PT101[i]=parseFloat(data.PT101).toFixed(2);
				tab_PT103[i]=parseFloat(data.PT103).toFixed(2);
				tab_PT110[i]=parseFloat(data.PT110).toFixed(2);
				tab_PT205[i]=parseFloat(data.PT205).toFixed(2);
				
				l_PT101.innerHTML = tab_PT101[i]+" "+ "[bar]";
				l_PT103.innerHTML = tab_PT103[i]+" "+ "[bar]";
				l_PT110.innerHTML = tab_PT110[i]+" "+ "[bar]";
				l_PT205.innerHTML = tab_PT205[i]+" "+ "[bar]";
				
				return data;
});	
0

Po raz kolejny podbijam. Przeczytałem książka Pana Stoyanowa (Programowania Obiektowe Java Script), całkiem sporo ciekawych rzeczy się po niej dowiedziałem, jednak problemu w dalszym ciągu nie potrafię rozwiązać. Z rozdziału o DOM wynotowałem sobie, że:

Problem polega na tym, że jeśli wiele obserwatorów jest dołączonych do usuwanych elementów, IE nie usunie obserwatorów, co prowadzi do wycieków pamięci (przechowywane są referencje do nieistniejących elementów). Zaimplementuj ogólną funkcję, która usuwa węzły DOM , najpierw usuwając związanych z nimi obserwatorów. Możesz przejść iteracyjnie przez wszystkie atrybuty węzła, sprawdzając, czy wartość któregoś z nich nie jest funkcją. Jeśli jest, prawdopodobnie jest to atrybut podobny do oncl i ck. Musisz przypisać mu wartość nul 1 przed usunięciem danego elementu z drzewa.

Wrzuciłem na sterownik jedynie:

<!DOCTYPE html>
<html lang="en">

    <head>
		<meta charset="utf-8">
		<title>Web Server</title>
		<script src="jquery-2.1.3.min.js"></script>
		<link href="traci.css" type="text/css" rel="stylesheet" />
    </head>
	
    <body>
		<p><img class="Schematic" src="Traci.jpg" alt="zdjecie"></p>
		<label class="l_Name" id="l_Name">web</label>
		<label class="l_autor">autor</label>	

		 <label class="l_TT101" id="l_TT101">TT101</label>
		 <label class="l_TT102" id="l_TT102">TT102</label>
		 <label class="l_TT103" id="l_TT103">TT103</label>
		 <label class="l_TT104" id="l_TT104">TT104</label>
		 <label class="l_TT105" id="l_TT105">TT105</label>
		 <label class="l_TT106" id="l_TT106">TT106</label>
		 <label class="l_TT110" id="l_TT110">TT110</label>
		 <label class="l_TT205A" id="l_TT205A">TT205A</label>
		 <label class="l_TT205B" id="l_TT205B">TT205B</label>
		 <label class="l_TTEX01" id="l_TTEX01">TT_EX01</label>
		 <label class="l_PT101" id="l_PT101">PT101</label>
		 <label class="l_PT103" id="l_PT103">PT103</label>
		 <label class="l_PT110" id="l_PT110">PT110</label>
		 <label class="l_PT205" id="l_PT205">PT205</label>
		 <label class="l_FT103" id="l_FT103">FT103</label>
		 <label class="l_DP101" id="l_DP101">DP101</label>
		 <label class="l_SC101" id="l_SC101">SC101</label>
		 <label class="l_SC102" id="l_SC102">SC102</label>
		 <label class="l_SC103" id="l_SC103">SC103</label>
		 <label class="l_speed" id="l_speed">Speed</label>
		 
		 <label class="lt_TT101" id="lt_TT101">TT101:</label>
		 <label class="lt_TT102" id="lt_TT102">TT102:</label>
		 <label class="lt_TT103" id="lt_TT103">TT103:</label>
		 <label class="lt_TT104" id="lt_TT104">TT104:</label>
		 <label class="lt_TT105" id="lt_TT105">TT105:</label>
		 <label class="lt_TT106" id="lt_TT106">TT106:</label>
		 <label class="lt_TT110" id="lt_TT110">TT110:</label>
		 <label class="lt_TT205A" id="lt_TT205A">TT205A:</label>
		 <label class="lt_TT205B" id="lt_TT205B">TT205B:</label>
		 <label class="lt_TT_EX01" id="lt_TT_EX01">TT_EX01:</label>
		 <label class="lt_PT101" id="lt_PT101">PT101:</label>
		 <label class="lt_PT103" id="lt_PT103">PT103:</label>
		 <label class="lt_PT110" id="lt_PT110">PT110:</label>
		 <label class="lt_PT205" id="lt_PT205">PT205:</label>
		 <label class="lt_FT103" id="lt_FT103">FT103:</label>
		 <label class="lt_DP101" id="lt_DP101">DP101:</label>
		 <label class="lt_SC101" id="lt_SC101">SC101:</label>
		 <label class="lt_SC102" id="lt_SC102">SC102:</label>
		 <label class="lt_SC103" id="lt_SC103">SC103:</label>
		 <label class="lt_speed" id="lt_speed">Speed:</label>
    </body>
	
    <script type="text/javascript">

	var i = 0; //iteration

	//T
	var tab_TT101=[];
	var tab_TT102=[];
	var tab_TT103=[];
	var tab_TT104=[];
	var tab_TT105=[];
	var tab_TT106=[];
	var tab_TT110=[];
	var tab_TT205A=[];
	var tab_TT205B=[];
	var tab_TTEX01=[];
	
	l_TT101=document.getElementById("l_TT101");
	l_TT102=document.getElementById("l_TT102");
	l_TT103=document.getElementById("l_TT103");
	l_TT104=document.getElementById("l_TT104");
	l_TT105=document.getElementById("l_TT105");
	l_TT106=document.getElementById("l_TT106");
	l_TT110=document.getElementById("l_TT110");
	l_TT205A=document.getElementById("l_TT205A");
	l_TT205B=document.getElementById("l_TT205B");
	l_TTEX01=document.getElementById("l_TTEX01");
	
    $(document).ready(function(){
	
        $.ajaxSetup({ cache: false });

        setInterval(function() {	
			
			$.getJSON("I_Temperatures.htm", function(data){		
					
				tab_TT101[i]=parseFloat(data.TT101);
				tab_TT102[i]=parseFloat(data.TT102);
				tab_TT103[i]=parseFloat(data.TT103);
				tab_TT104[i]=parseFloat(data.TT104);
				tab_TT105[i]=parseFloat(data.TT105);
				tab_TT106[i]=parseFloat(data.TT106);
				tab_TT110[i]=parseFloat(data.TT110);
				tab_TT205A[i]=parseFloat(data.TT205A);
				tab_TT205B[i]=parseFloat(data.TT205B);
				tab_TTEX01[i]=parseFloat(data.TTEX01);
				
				l_TT101.innerHTML = tab_TT101[i]+ " " + "°C";
				l_TT102.innerHTML = tab_TT102[i]+ " " + "°C";
				l_TT103.innerHTML = tab_TT103[i]+ " " + "°C";
				l_TT104.innerHTML = tab_TT104[i]+ " " + "°C";
				l_TT105.innerHTML = tab_TT105[i]+ " " + "°C";
				l_TT106.innerHTML = tab_TT106[i]+ " " + "°C";
				l_TT110.innerHTML = tab_TT110[i]+ " " + "°C";
				l_TT205A.innerHTML = tab_TT205A[i]+ " " + "°C";
				l_TT205B.innerHTML = tab_TT205B[i]+ " " + "°C";
				l_TTEX01.innerHTML = tab_TTEX01[i]+ " " + "°C";
				
				return data;
					
			});	

			i++;
			
			if(i==100){
				tab_TT101.splice(0,tab_TT101.length);
				tab_TT102.splice(0,tab_TT102.length);
				tab_TT103.splice(0,tab_TT103.length);
				tab_TT104.splice(0,tab_TT104.length);
				tab_TT105.splice(0,tab_TT105.length);
				tab_TT106.splice(0,tab_TT106.length);
				tab_TT110.splice(0,tab_TT110.length);
				tab_TT205A.splice(0,tab_TT205A.length);
				tab_TT205B.splice(0,tab_TT205B.length);
				tab_TT_EX01.splice(0,tab_TT_EX01.length);
				i=0;
			}
			
        },1000);		
	});

    </script>
	
</html>

Załączam zdjęcia:

user image

I już tylko to mi zapełnia pamięć. Z porad rozumiem, że mam usunąć obserwatorów (nie mam ich, ale widze, że listeners cały czas rośnie), mam znaleźć węzły i usunąć ich atrybuty które mogą być funkcjami, ale ich również nie mam. Tzn, że powinienem usuwać każdego po załadowaniu tab_TTxxx?

Bardzo proszę, chociaż o naprowadzenie mnie na właściwe tory.

1

Spróbuj nie korzystać z globali. Zamiast raz wybierać elementy DOM - wybieraj je za każdym razem w pętli. Pozbywaj się też danych, z których nie korzystasz.

Na razie zrób (możesz dodać te kolejne dane, ja tu tylko skracam, żeby przykład pokazać) np:

    $(document).ready(function(){
        $.ajaxSetup({ cache: false });
        setInterval(function() {     
            $.getJSON("I_Temperatures.htm", function(data){        
                var tab_TT101=parseFloat(data.TT101);
                var l_TT101=document.getElementById("l_TT101");

                l_TT101.innerHTML = tab_TT101+" *C";
            });    
        },1000);        
    });
 
0

Wielkie dzięki za rady.
Jutro rano na pewno je przetestuje.
Usuwać dane z których nie korzystam wystarczy np.:

tab_TT101 = null;

Czy może lepiej?

delete tab_TT101;
0

null

0

Dzięki wielkie za pomoc.
Wydłużyłem interval do 5 sekund i problem z listenerami zniknął.
Wykorzystuje jedynie zmienne lokalne i je usuwam i też, wydaje mi się, że lepiej działa.
Jedyne co stale ulega zwiększeniu to "Used JS Heap" - czy powinienem się tym przejmować? Sprawdziłem na google.pl i tam też "Used JS Heap" z upływem czasu się zwiększa.

Sprawdziłem, przez półtorej godziny działania wyglądało to tak (na w pełni funkcjonalnym web serverze):

user image

0

Ok WebServer wytrzymuje już 24 godziny bez zwieszenie, więc uważam, że jest (na razie) dobrze.
Co zrobiłem: wykomentowałem funkcje rysujące, zminimalizowałem jak tylko mogłem ilośc zmiennych globalnych.
Niemniej jednak rysowanie wykresów jest mi potrzebne, wykorzystuję do tego tą biblioteke: jqPlot (http://www.jqplot.com/)

Kod zmodyfikowałem już w ten sposób, żeby za każdym razem usuwało wykres i wstawiało nowy z nowymi danymi, jednak nie wiele to pomogło.

Jak myślicie czy dodanie dla zmiennej "plot1" prefixu "var" może rozwiązać sprawę? Czy pomijam tutaj jakąś inną, bardzo ważną sprawę?

	
function rysuj_temp(){
					
		$("#w_temp").remove();		
		var w_t = document.createElement('div');
		w_t.id = 'w_temp';
		w_t.style.top="90px";
		w_t.style.left = "880px";
		w_t.style.width = "1000px";
		w_t.style.height = "400px";
		w_t.style.visibility = "visible";
		
		$("body").append(w_t);
		
		var labels = ['TT101', 'TT102','TT103', 'TT104','TT105', 'TT106','TT110', 'TT205A', 'TT205B', 'TT_EX01']
		//T
		$("#w_temp").empty();	
		plot1 = $.jqplot ('w_temp', [tab_TT101w, tab_TT102w, tab_TT103w, tab_TT104w, tab_TT105w, tab_TT106w, tab_TT110w, tab_TT205Aw, tab_TT205Bw, tab_TT_EX01w], {
			title: 'Temperatures',			
			legend: {
				show: true,
				renderer: $.jqplot.EnhancedLegendRenderer, //hide line
				rendererOptions: {
					numberRows: 2
				},
				placement: 'outsideGrid',
				labels: labels,
				location: 's'				
			},
			seriesDefaults: {
				showMarker: false,
            },
			axesDefaults: {
				labelRenderer: $.jqplot.CanvasAxisLabelRenderer
			},
			axes: {
				xaxis: {
					renderer:$.jqplot.DateAxisRenderer,		
	                rendererOptions:{
						tickRenderer:$.jqplot.CanvasAxisTickRenderer
                    },
					tickOptions:{
						formatString:'%d-%B-%Y %H:%M:%S',
						fontSize:'7pt', 
						angle: -40
					},
					label: "Time",		
					pad: 0
				},
				yaxis: {
					label: "°C",
					labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
					tickOptions: {
					  formatter: $.jqplot.PercentTickFormatter,
					  showGridline: false,
					  suffix: '°C'
					}					
				}	
			},
			cursor:{
				zoom:true
			}
		});		
	
	}
1

Upewnij się, że robisz destroy tego jqplot tak jak należy, z poziomu API, a nie usuwasz po prostu diva w którym to trzymasz.
var zawsze lepiej mieć niż nie mieć, jeżeli nie psuje to Twojego kodu

0

O widzisz trafiłeś w "10". Biblioteka jqplot ma funkcje wbudowaną "this.destroy()".

Moje pytanie teraz brzmi, czy mogę to wrzucić zamiast: "$("#w_temp").remove();" i usuwać tak jak teraz (czyli w następnym cyklu). Czy muszę koniecznie kombinować i usuwać to w bieżącym cyklu setInterval(), czy nie ma to większego znaczenia?

No właśnie wyrzucić w takim wypadku usuwanie tego diva i tworzyć go na nowo, czy to zostawić? Będzie to miało jakieś znaczenie?

Drugie pytanie:
W jedym z poradników znalazłem, że lepiej nie mieszać elementów w talicach.
U mnie wygląda to tak, że odczytuje danych i wrzucam je w tablice.
Jeżeli są jakieś zakłócenia przy odbieraniu informacji pojawia się komunikat "undefined", jak jakaś nieprawidłowa wartośc może być liczona to "NaN'. Czy powinienem te sytuacje wyłapywać i wrzucać w te przypadki i wrzucać komunikaty błędów? Np zamiast "undefined" dać -9999, a "NaN" dać - 9998?

1

Od końca: Nie, to bez sensu. Nie ma to znaczenia na wyciek pamięci, jedynie w jakiś sposób na wydajność, ale Ty nie piszesz gry 3D z 60fps, tylko wykres odświeżany co sekundę czy coś.

Diva możesz zostawić, możesz usunąć.

Do pierwszego pytania się nie odniosę, bo nie mam całości nowego kodu.

0

Do pierwszego pytania. Mniej więcej wygląda to tak:

setInterval(function(){
         //Tutaj jest kod
         rysuj();
},5000)	
//......
function rysuj_temp(){
		
		var plot1;
		plot1.destroy(); //<<---------------- Tutaj wstawiam linie z destroy	
		var labels = ['TT101', 'TT102','TT103', 'TT104','TT105', 'TT106','TT110', 'TT205A', 'TT205B', 'TT_EX01']
		$("#w_temp").empty();
		plot1 = $.jqplot ('w_temp', [tab_TT101w, tab_TT102w, tab_TT103w, tab_TT104w, tab_TT105w, tab_TT106w, tab_TT110w, tab_TT205Aw, tab_TT205Bw, tab_TT_EX01w], {
		
1

Tak jak jest powinno być ok

0

Bardzo dziękuję za cierpliwość! Zbliżam się chyba do końca.

Powiedz mi, bo wcześniej usuwałem elementy z tablic przez:

var tab=[];
tab.splice(0,tab.length);

Czy lepiej jest to robić w ten sposób:

var tab=[];
tab = null;

Jeżeli drugi to jak później deklarować nowe tablice?

var tab=[];
//1 opcja:
tab = new Array();
//Czy może:
tab = [];

Jeszcze mi przyszło do głowy:
Głównym zadaniem serwera jest monitorowanie, zbieranie danych i rysowanie wykresów.
Jeżeli ten server ma długo działać, dobrym pomysłem byłoby zapisanie w cookies kiedy został uruchomiony i z jakimi parametrami.
Tak aby po upływie np. 24 godzin strona się odświeżyła i od razu uruchomił proces zbierania danych z tymi samymi parametrami (odczytanymi z cookies)?
Czy jest to absoluetnie nie możliwe do zrobienia?

1

a to przed rozpoczęciem zbierania danych ustawiasz jakieś parametry? użyj sobie localStorage zamiast ciastek, a czasu uruchomienia nie musisz zapisywać - wystarczy setTimeout po rozpoczęciu zbierania danych ;)

zmienne czyść po prostu nadpisując zmienna pusta tablica
var X = []

0

Ogromnie dziękuje za pomoc i cierpliwość do mnie.

Ok przeglądne te localStorage, chociaż możliwe, że nie będą już potrzebne.
Puściłem na całą noc i pamięć zajęta cały czas wachała się w przedziałach: 15 000K - 8 000K (live) - więc wynik które mnie bardzo zadowala.
Pojawił sie jednak inny problem, którego wcześniej nie spotkałem, od trzech plików z których wartości chciałem odczytywać, dostawałem komunikat:

net::err_insufficient_resources

Zauważyłem, że wydłużył się dziwnie czas "Waiting (TTFB)" jak sprawdzam odpowiedź z serwera. (i to niezależnie, czy korzystam z wykresów, czy nie)

Pozostałe funkcje działały bez zarzutu.

0

Brzmi źle.
Jak wiele danych zwraca Twój request?
Poobserwuj zakładkę "Sieć", czy przypadkiem requestów nie mnoży się z czasem (bo np. wywołujesz jakiegoś setInterval wewnątrz innego setInterval)

Wrzuć jak możesz cały kod.

0

Ta część kodu odpowiada za odbiór danych, wrzucona jest w SetInterval co 5000ms (dane musza być aktualizowane w czasie):
Żaden setInterval w setInterval nie jest wywoływany.
Czy może to być związane np. z obciążeniem sieci? - ten błąd pojawia się bardzo nieregularnie.
Jeszcze zastanawiałem się czy można czekać aż odpowiedź zostanie zwrócona, jeżeli nie to nie wykonywać następnego setInterval?
Np wewnątrz każdego z $.getJSON dać zmienną jak poniżej

var skonczone =1;
return data, skonczone;

Pozniej sprawdzac czy wszystkie funkcje zwróciły swoją wartość i dopiero wywołać setInterval (albo następny $.getJSON) jeżeli wszystkie dane zostały odebrane.

			$.getJSON("I_Temperatures.htm", function(data){		
					
					tab_TT101[i]=parseFloat(data.TT101);
					tab_TT102[i]=parseFloat(data.TT102);
					tab_TT103[i]=parseFloat(data.TT103);
					tab_TT104[i]=parseFloat(data.TT104);
					tab_TT105[i]=parseFloat(data.TT105);
					tab_TT106[i]=parseFloat(data.TT106);
					tab_TT110[i]=parseFloat(data.TT110);
					tab_TT205A[i]=parseFloat(data.TT205A);
					tab_TT205B[i]=parseFloat(data.TT205B);
					tab_TT_EX01[i]=parseFloat(data.TT_EX01);
					
					document.getElementById("TT_101").innerHTML = tab_TT101[i]+ " °C";
					document.getElementById("TT_102").innerHTML = tab_TT102[i]+ " °C";
					document.getElementById("TT_103").innerHTML = tab_TT103[i]+ " °C";
					document.getElementById("TT_104").innerHTML = tab_TT104[i]+ " °C";
					document.getElementById("TT_105").innerHTML = tab_TT105[i]+ " °C";
					document.getElementById("TT_106").innerHTML = tab_TT106[i]+ " °C";
					document.getElementById("TT_110").innerHTML = tab_TT110[i]+ " °C";
					document.getElementById("TT_205A").innerHTML = tab_TT205A[i]+ " °C";
					document.getElementById("TT_205B").innerHTML = tab_TT205B[i]+ " °C";
					document.getElementById("TT_EX01").innerHTML = tab_TT_EX01[i]+ " °C";
					
					return data;					
				});	

			$.getJSON("I_Pressures.htm", function(data){
					
					tab_PT101[i]=parseFloat(data.PT101).toFixed(2);
					tab_PT103[i]=parseFloat(data.PT103).toFixed(2);
					tab_PT110[i]=parseFloat(data.PT110).toFixed(2);
					tab_PT205[i]=parseFloat(data.PT205).toFixed(2);
					
					document.getElementById("PT_101").innerHTML = tab_PT101[i]+" [bar]";
					document.getElementById("PT_103").innerHTML = tab_PT103[i]+" [bar]";
					document.getElementById("PT_110").innerHTML = tab_PT110[i]+" [bar]";
					document.getElementById("PT_205").innerHTML = tab_PT205[i]+" [bar]";
					
					return data;
				});	
				
			$.getJSON("I_Flow.htm", function(data){		
					
					tab_FT103[i] = parseFloat(data.FT103).toFixed(2);
					document.getElementById("FT_103").innerHTML = tab_FT103[i]+" [g/s]";
					
					return data;
				});
				
			$.getJSON("I_SpeedRequest.htm", function(data){		
					
					tab_speed[i] = parseFloat(data.speed).toFixed(2);
					document.getElementById("l_speed").innerHTML = tab_speed[i]+" [rpm]";
					
					return data;
				});			
				
			$.getJSON("I_ForceHeater.htm", function(data){
					
					tab_HT110[i]=parseFloat(data.fHT110).toFixed(2);
					document.getElementById("HT_110").innerHTML = tab_HT110[i]+" °C";
					
					return data;
				});		

			$.getJSON("I_Calculated.htm", function(data){
					
					tab_DP101[i]=parseFloat(data.DP101).toFixed(2);
					tab_SC101[i]=parseFloat(data.SC101).toFixed(2);
					tab_SC102[i]=parseFloat(data.SC103).toFixed(2);
					tab_SC103[i]=parseFloat(data.SC103).toFixed(2);
					
					document.getElementById("DP_101").innerHTML = tab_DP101[i]+" [bar]";
					document.getElementById("SC_101").innerHTML = tab_SC101[i]+" °C";
					document.getElementById("SC_102").innerHTML = tab_SC102[i]+" °C";
					document.getElementById("SC_103").innerHTML = tab_SC103[i]+" °C";
					
					
					return data;
				});	

			$.getJSON("Status.htm", function(data){
					
					status=data.Start;
					
					return data;
				});
0

Po co Ci to return data? ;)
Spróbuj nie pchać tych żądań wszystkich naraz, bo możliwe, że błąd Ci wywala dlatego, że przeglądarka ma limit połączeń do jednej domeny (choć wydaje mi się, że powinna wtedy czekać) tylko lecieć je po kolei. Żeby nie nakładać na siebie milion callbacków możesz zainsteresować się mechanizmem obietnic (js promises, np: http://javascriptplayground.com/blog/2015/02/promises/ - problem, że ja sam nie poznałem jeszcze tego, więc będę musiał się doaktualizować, żeby Ci potem pomóc ;P)

0

Ogromnie dziękuję! ;)

Na ten moment wystarczyło wyrzucić

return data;

W konfiguracji sterownika dałem mu więcej czasu na komunikacje i problemy się rozwiązały.

1 użytkowników online, w tym zalogowanych: 0, gości: 1