<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Lesson 11. TV out. Weather broadcast]]></title><description><![CDATA[<h2>The purpose of this lesson</h2>
<p dir="auto">Hi! Today we will learn how to connect the TV to M5 STACK and display images and text on it by means of a video signal (Fig. 1).</p>
<p dir="auto"><img src="https://sun1-2.userapi.com/c840721/v840721542/79bda/_HYrFnOd4T4.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 1</p>
<p dir="auto">You need to make the gateway M5 black periodically received weather information at the moment from <a href="https://openweathermap.org" title="https://openweathermap.org" target="_blank" rel="noopener noreferrer nofollow ugc">https://openweathermap.org</a> and passed it to via radio 433 MHz, and M5 gray took this information and displayed graphically on a TV.<br />
Black installed in M5 TF card with Wi-Fi settings network parameters of the service <a href="http://openweathermap.org" target="_blank" rel="noopener noreferrer nofollow ugc">openweathermap.org</a>.</p>
<p dir="auto">When the device is turned on, the user will prompt to insert the memory card. The following files will be located on the memory card (Fig. 1.1):</p>
<ul>
<li>file with known Wi-Fi networks (system/wifi.ini);</li>
<li>the style file (system/openweather.ini) (Fig. 1.2).</li>
</ul>
<p dir="auto"><img src="https://sun1-3.userapi.com/c840721/v840721542/79bf1/3jbfhgB4ABw.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 1.1. The contents of the folder system</p>
<p dir="auto"><img src="https://sun1-3.userapi.com/c840721/v840721542/79bfa/hly1Put6ZDQ.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 1.2. The contents of the openweather file.ini</p>
<h2>Short help</h2>
<p dir="auto">A video signal is an electrical signal of a special form (Fig. 2) by means of which the television image is transmitted.<br />
The concept of video signal is applicable to both analog and digital television, as well as to information display systems of computers based on electron-beam tubes.<br />
The instantaneous value of the illumination on the photosensitive surface of the television photodetector is converted into an instantaneous value of the voltage at the output of this photodetector. Thus, in the video signal voltage is proportional to the brightness at a given point in the image. This part of the video signal is called a brightness signal and is used to transmit a black and white video signal or a brightness signal in a color video signal. The range of transmitted brightness values is determined by the level of black and white signals in the video signal. Black level is a minimum luminance signal and corresponds to synchronization signals. It is also simultaneously a reference signal. The white level corresponds to the maximum transmitted brightness level. In addition to the brightness signal, the video signal contains service components that ensure synchronization of the signal between the source and the receiver. There are two types of synchronization signals – string and frame. Frame synchronization signals provide information about the start time of each field of the television image in the video signal, as well as information about the type of this field (even or odd).</p>
<p dir="auto"><img src="https://sun9-1.userapi.com/c840721/v840721286/7c5ae/O1eveSL7Cio.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 2. The oscillogram of the video signal 4 µs - blanking pulse, 8 MS - color information, 52 MKS - brightness signal</p>
<h2><strong>List of components for the lesson</strong></h2>
<ul>
<li>M5STACK (2 PCs.);</li>
<li>USB-C cable from standard set;</li>
<li>4GB MicroSD memory card;</li>
<li>colored wires from the standard set (socket type-plug);</li>
<li>radio MX-JS-05V;</li>
<li>radio transmitter FS1000A;</li>
<li>TV that supports PAL video;</li>
<li>RCA plug;</li>
<li>soldering iron and solder;</li>
<li>shrinkage.</li>
</ul>
<h2>Begin!</h2>
<h3>Step 1. Register on the site <a href="http://openweathermap.org" target="_blank" rel="noopener noreferrer nofollow ugc">openweathermap.org</a></h3>
<p dir="auto">In order to receive weather information you need to register on this resource. Registration is absolutely free and will not take much time (Fig. 3).</p>
<p dir="auto"><img src="https://pp.userapi.com/c844320/v844320178/2ec3b/pl9dY3gDgRQ.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3. Registration on the website</p>
<p dir="auto">After registering in your personal account on the site, go to the section <strong>API keys</strong> and get** Key** access to the service.</p>
<p dir="auto"><img src="https://pp.userapi.com/c844320/v844320178/2ec52/W1Iz5sKjFpQ.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3.1. Getting an API key</p>
<p dir="auto">So registration site is completed.</p>
<h3>Step 2. Make an adapter to connect to TV</h3>
<p dir="auto">Here - just do. Most importantly, remember that the colored wire should be soldered to the Central contact of the RCA plug (Fig. 4 - 4.2).</p>
<p dir="auto"><img src="https://pp.userapi.com/c844320/v844320178/2ec6e/grXTDOpOcmY.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4.</p>
<p dir="auto"><img src="https://pp.userapi.com/c844320/v844320178/2ec81/dTxglfzEJiU.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4.1</p>
<p dir="auto"><img src="https://pp.userapi.com/c844320/v844320178/2ec77/0-lDL2pwtaE.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4.2</p>
<h3>Step 3. Write a sketch for the gateway on m5 black</h3>
<p dir="auto">In order to obtain information from the site using the GET-request will write a simple function. As an argument, the function takes a GET query string, and returns the server response as a string:</p>
<pre><code>String GET(String url) {
  while (true)
  {
    if ((wifiMulti.run() == WL_CONNECTED))
    {
      HTTPClient http;
      http.begin(url);
      int httpCode = http.GET();
      if (httpCode &gt; 0)
      {
          if (httpCode == HTTP_CODE_OK)
          {
            return http.getString();
          }
      }
      else
      {
        return (httpCode + "");
      }
      http.end();
    }
  }  
  return ""; 
}
</code></pre>
<p dir="auto">All configuration information for the openweathermap service, as mentioned earlier, will be stored on the TF-card. Therefore, we need to write a function to generate a GET request:</p>
<blockquote>
<p dir="auto">Note-service <strong>nl.lego.city</strong> -returns information about your location based on the IP address that you do not need to send in a GET request.</p>
</blockquote>
<pre><code>String configOpenWeather() {
  String file = TFReadFile("/system/openweather.ini");
  if (file != "")
  {  
    String city = "&amp;q=" + parseString(1, '\"', parseString(1, ':', parseString(5, ',', GET("http://nl.sxgeo.city/?")))); 
    String api_key = "&amp;APPID=" + parseString(0, ' ', file);
    String app_id = "&amp;id=" + parseString(1, ' ', file);
    String lang = "&amp;lang=" + parseString(2, ' ', file);
    String units = "&amp;units=" + parseString(3, ' ', file);
    String host = "http://api.openweathermap.org/data/2.5/weather?";
    String url_ = host + city + api_key + app_id + lang + units;
    return url_;
  }
  return "";
}
</code></pre>
<p dir="auto">In one of the previous lessons we discussed the function of setting up the wifi using the parameters obtained from the TF card. This time we will modify the body of the function, add the ability to save the configuration file under the operating system MacOS X. The fact that the Mac adds one special. a character at the end of a string is not like Windows-two.</p>
<pre><code>bool configWifiMulti() {
  /* Get WiFi SSID &amp; password from wifi.ini from TF-card */
  String file = TFReadFile("/system/wifi.ini");
  if (file != "")
  {
    for (int i = 0; i &lt; cntChrs(file, '\n'); i++)
    {
      String wifi = parseString(i, '\n', file);
      wifi = wifi.substring(0, (wifi.length()));
      if (wifi[wifi.length() - 1] == '\r') wifi = wifi.substring(0, (wifi.length() - 1));
      String ssid = parseString(0, ' ', wifi);
      String pswd = parseString(1, ' ', wifi);
      char* ssid_ = strToChar(ssid);
      char* pswd_ = strToChar(pswd);
      if (wifiMulti.addAP(ssid_, pswd_))
      {
        return true;
      }
    }
  }
  return false;
}
</code></pre>
<p dir="auto">Using the following lines of code, we will extract the necessary data from the server response:</p>
<pre><code>temp = parseString(2, ':', parseString(7, ',', weather));
pres = parseString(1, ':', parseString(8, ',', weather));
hum = parseString(1, ':', parseString(9, ',', weather));
desc = parseString(1, '"', parseString(1, ':', parseString(4, ',', weather))); 
weatherIcon = parseString(1, '"', parseString(1, ':', parseString(5, ',', weather)));
</code></pre>
<p dir="auto">Next, we will share the data with the help of a special symbol and send it to the radio:</p>
<pre><code>sendString("1" + String((char)0x1d) + temp);
delay(1);
sendString("2" + String((char)0x1d) + String(round(pres.toInt() * 0.75)));
delay(1);
sendString("3" + String((char)0x1d) + hum);
delay(1);
sendString("4" + String((char)0x1d) + desc);
delay(1);
sendString("5" + String((char)0x1d) + weatherIcon);
delay(1);	
</code></pre>
<p dir="auto">So writing the sketch for the transmitter is finished.</p>
<h3>Step 4. Now write a sketch for the receiver on m5 gray</h3>
<p dir="auto">To display the image on TV, we will use the author's library <a href="http://bitluni.net/esp32-composite-video/" title="http://bitluni.net/esp32-composite-video/" target="_blank" rel="noopener noreferrer nofollow ugc">http://bitluni.net/esp32-composite-video/</a>. Because the library uses both DAC channels, you had to modify the library a little to disable the left channel. I have simplified the procedure of using the library by placing the most important thing in the header file <em>m5stack_tv.h</em>:</p>
<pre><code>namespace m5stack_tv
{
  #include "CompositeGraphics.h"
  #include "Image.h"
  #include "CompositeOutput.h"
  #include &lt;soc/rtc.h&gt;
  #include "font6x8.h"
  
  const int XRES = 320;
  const int YRES = 200;

  CompositeGraphics graphics(XRES, YRES);
  CompositeOutput composite(CompositeOutput::NTSC, XRES * 2, YRES * 2);
  Font&lt;CompositeGraphics&gt; font(6, 8, font6x8::pixels);

  char* strToChar(String str) {
    int len = str.length() + 1;
    char* buf = new char[len];
    strcpy(buf, str.c_str());
    return buf;
  }

  void compositeCore(void *data) {  
    while (true)
    {
      composite.sendFrameHalfResolution(&amp;graphics.frame);
    }
  }
  
  void begin() {
    rtc_clk_cpu_freq_set(RTC_CPU_FREQ_240M);
    composite.init();
    graphics.init();
    graphics.setFont(font);
    xTaskCreatePinnedToCore(compositeCore, "c", 2048, NULL, 1, NULL, 0);
  }

  void setTextColor(int c) {
    graphics.setTextColor(c);
  }
  
  void setCursor(int x, int y) {
    graphics.setCursor(x, y);
  }

  void print(String str) {
    graphics.print(strToChar(str));
  }

  void drawBitmap(int x, int y, int w, int h, const unsigned char* img) {   
    Image&lt;CompositeGraphics&gt; img_(w, h, img);
    img_.draw(graphics, x, y);
  }

  void fillRect(int x, int y, int w, int h, int color = 0) {
    graphics.fillRect(x, y, w, h, color);
  }

  void drawDot(int x, int y, int color) {
    graphics.dotFast(x, y, color);
  }

  void clearScreen(int color = 0) {
    fillRect(0, 0, XRES, YRES, color);
  }
}
</code></pre>
<blockquote>
<p dir="auto">Please note: the image format is different from what we saw in the lessons on working with the built-in display. In order to convert the image to display it on TV, you need to use the Converter program from the "Downloads".</p>
</blockquote>
<p dir="auto">Let's write a function that, depending on the weather icon code, will display the image on the screen:</p>
<pre><code>void drawWeatherIcon(int x, int y, String str) {
  if (str == "01d") m5stack_tv::drawBitmap(x, y, _01d::xres, _01d::yres, _01d::pixels);
  else if (str == "01n") m5stack_tv::drawBitmap(x, y, _01n::xres, _01n::yres, _01n::pixels);
  else if (str == "02d") m5stack_tv::drawBitmap(x, y, _02d::xres, _02d::yres, _02d::pixels);
  else if (str == "02n") m5stack_tv::drawBitmap(x, y, _02n::xres, _02n::yres, _02n::pixels);
  else if (str == "03d") m5stack_tv::drawBitmap(x, y, _03d::xres, _03d::yres, _03d::pixels);
  else if (str == "03n") m5stack_tv::drawBitmap(x, y, _03n::xres, _03n::yres, _03n::pixels);
  else if (str == "04d") m5stack_tv::drawBitmap(x, y, _04d::xres, _04d::yres, _04d::pixels);
  else if (str == "04n") m5stack_tv::drawBitmap(x, y, _04n::xres, _04n::yres, _04n::pixels);
  else if (str == "09d") m5stack_tv::drawBitmap(x, y, _09d::xres, _09d::yres, _09d::pixels);
  else if (str == "09n") m5stack_tv::drawBitmap(x, y, _09n::xres, _09n::yres, _09n::pixels);
  else if (str == "10d") m5stack_tv::drawBitmap(x, y, _10d::xres, _10d::yres, _10d::pixels);
  else if (str == "10n") m5stack_tv::drawBitmap(x, y, _10n::xres, _10n::yres, _10n::pixels);
  else if (str == "11d") m5stack_tv::drawBitmap(x, y, _11d::xres, _11d::yres, _11d::pixels);
  else if (str == "11n") m5stack_tv::drawBitmap(x, y, _11n::xres, _11n::yres, _11n::pixels);
  else if (str == "13d") m5stack_tv::drawBitmap(x, y, _13d::xres, _13d::yres, _13d::pixels);
  else if (str == "13n") m5stack_tv::drawBitmap(x, y, _13n::xres, _13n::yres, _13n::pixels);
  else if (str == "50d") m5stack_tv::drawBitmap(x, y, _50d::xres, _50d::yres, _50d::pixels);
  else if (str == "50n") m5stack_tv::drawBitmap(x, y, _50n::xres, _50n::yres, _50n::pixels);
}
</code></pre>
<p dir="auto">Let's connect the images to the header file:</p>
<pre><code>#include "weatherIcons/main.h"
</code></pre>
<p dir="auto">Starting is performed by calling the method:</p>
<pre><code>m5stack_tv::begin();
</code></pre>
<p dir="auto">Therefore, when receiving the weather information will be immediately displayed on the TV:</p>
<pre><code>void loop() { 
  if (radioRX.available(&amp;k))
  {
    message("data accepted");
    radioRX.read(&amp;j, sizeof(j));
    delay(1);
    message(j);
    int type = (parseString(0, (char)0x1d, j)).toInt();
    String data = parseString(1, (char)0x1d, j);
    if (type == 1) temp = data;
    else if (type == 2) pres = data;
    else if (type == 3) hum = data;
    else if (type == 4) desc = data; 
    else if (type == 5) icon = data;
    
    if (type &gt; 0)
    {
      m5stack_tv::setTextColor(0);
      m5stack_tv::clearScreen(54);
      message("drawing on TV");  
      m5stack_tv::setCursor(140, 60);
      m5stack_tv::print("Temperature, C: " + temp);
      m5stack_tv::setCursor(140, 80);
      m5stack_tv::print("Humidity, %: " + hum);
      m5stack_tv::setCursor(140, 100);
      m5stack_tv::print("Pressure, mm Hg: " + pres);
      m5stack_tv::setCursor(140, 120);
      m5stack_tv::print(desc);
      drawWeatherIcon(30, 45, icon);
    }
  }
}
</code></pre>
<p dir="auto">Step 5. Launch!<br />
In the section <strong>"Download"</strong> attached video demonstration. The lesson is completed.</p>
<h2>Downloads</h2>
<ul>
<li>Sketches and library (GitHub): <a href="https://github.com/dsiberia9s/TV-out.-Weather-broadcast" title="https://github.com/dsiberia9s/TV-out.-Weather-broadcast" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/dsiberia9s/TV-out.-Weather-broadcast</a></li>
<li>Image Converter for TV: <a href="https://yadi.sk/d/PzJVuAWj3UbLiv" title="https://yadi.sk/d/PzJVuAWj3UbLiv" target="_blank" rel="noopener noreferrer nofollow ugc">https://yadi.sk/d/PzJVuAWj3UbLiv</a></li>
<li>Video with demonstration of work (YouTube): <a href="https://youtu.be/OLJlK17hkDo" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/OLJlK17hkDo</a></li>
</ul>
]]></description><link>https://community.m5stack.com/topic/182/lesson-11-tv-out-weather-broadcast</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 15:14:00 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/182.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 20 Apr 2018 11:25:38 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Lesson 11. TV out. Weather broadcast on Mon, 10 Sep 2018 18:43:05 GMT]]></title><description><![CDATA[<p dir="auto">Hi. I´ve followed all your instructions and could even compile properly the code.<br />
The sketch is very simple cause I only want to produce the output on TV.</p>
<p dir="auto">#include &lt;M5Stack.h&gt;<br />
#include "m5stack_tv.h"</p>
<p dir="auto">void setup() {<br />
M5.begin();<br />
M5.Lcd.fillScreen(TFT_BLACK);<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextSize(3);<br />
M5.Lcd.setCursor(40,100);<br />
M5.Lcd.print("Working...");</p>
<p dir="auto">//  m5stack_tv::begin();<br />
}</p>
<p dir="auto">void loop() {<br />
m5stack_tv::setTextColor(0);<br />
m5stack_tv::clearScreen(54);<br />
m5stack_tv::setCursor(140, 60);<br />
m5stack_tv::print("Temperature, C: ");<br />
m5stack_tv::setCursor(140, 60);<br />
m5stack_tv::print("Temperature, C: ");<br />
m5stack_tv::setCursor(140, 80);<br />
m5stack_tv::print("Humidity, %: ");<br />
m5stack_tv::setCursor(140, 100);<br />
m5stack_tv::print("Pressure, mm Hg: ");</p>
<p dir="auto">}<br />
But when running, the screen of the m5stack starts flashing/blinking and there´s no signal on the TV.<br />
I´ve connected the central cable of the RCA to DAC 25 which is not stated in your article and the external RCA to ground.</p>
<p dir="auto">It seems like there´s a conflict between DAC 25 and the M5stack screen.<br />
If I comment in setup() the line that activates TVout:<br />
//m5stack_tv::begin()<br />
and everything on void() the m5 screens starts to work as intended, so the problem is within Tv library.</p>
<p dir="auto">I use M5stack basic (the black).</p>
<p dir="auto">Any help?</p>
]]></description><link>https://community.m5stack.com/post/1508</link><guid isPermaLink="true">https://community.m5stack.com/post/1508</guid><dc:creator><![CDATA[foroplus]]></dc:creator><pubDate>Mon, 10 Sep 2018 18:43:05 GMT</pubDate></item><item><title><![CDATA[Reply to Lesson 11. TV out. Weather broadcast on Fri, 18 May 2018 04:43:02 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/kakaxi123" aria-label="Profile: kakaxi123">@<bdi>kakaxi123</bdi></a> sure. you can see Lesson 5, Figure 5.1. Wi-Fi access.ini</p>
]]></description><link>https://community.m5stack.com/post/992</link><guid isPermaLink="true">https://community.m5stack.com/post/992</guid><dc:creator><![CDATA[Dimi]]></dc:creator><pubDate>Fri, 18 May 2018 04:43:02 GMT</pubDate></item><item><title><![CDATA[Reply to Lesson 11. TV out. Weather broadcast on Fri, 18 May 2018 01:03:39 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/dimi" aria-label="Profile: dimi">@<bdi>dimi</bdi></a><br />
hi，Thanks<br />
Can you provide the content of wifi.ini ？</p>
]]></description><link>https://community.m5stack.com/post/991</link><guid isPermaLink="true">https://community.m5stack.com/post/991</guid><dc:creator><![CDATA[KAKAXI123]]></dc:creator><pubDate>Fri, 18 May 2018 01:03:39 GMT</pubDate></item><item><title><![CDATA[Reply to Lesson 11. TV out. Weather broadcast on Thu, 17 May 2018 12:21:28 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/kakaxi123" aria-label="Profile: kakaxi123">@<bdi>kakaxi123</bdi></a> you can see example on the Figure 1.2. The contents of the openweather file.ini</p>
]]></description><link>https://community.m5stack.com/post/987</link><guid isPermaLink="true">https://community.m5stack.com/post/987</guid><dc:creator><![CDATA[Dimi]]></dc:creator><pubDate>Thu, 17 May 2018 12:21:28 GMT</pubDate></item><item><title><![CDATA[Reply to Lesson 11. TV out. Weather broadcast on Thu, 17 May 2018 09:40:27 GMT]]></title><description><![CDATA[<p dir="auto">would you like to share the files :openweather.ini and wifi.ini</p>
]]></description><link>https://community.m5stack.com/post/986</link><guid isPermaLink="true">https://community.m5stack.com/post/986</guid><dc:creator><![CDATA[KAKAXI123]]></dc:creator><pubDate>Thu, 17 May 2018 09:40:27 GMT</pubDate></item></channel></rss>