Ошибки в PlatformIO

Antsanv
Offline
Зарегистрирован: 18.12.2018

Добрый день.
Пытаюсь сделать многофайловый проект.

файл main.cpp

#include "config.h"

void setup() {
    Serial.begin(115200);
    WiFiManager wifiManager;
    //wifiManager.resetSettings();
    //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    wifiManager.autoConnect("AutoConnectAP");
    //or use this for auto generated name ESP + ChipID
    //wifiManager.autoConnect();
    Serial.println("connected... :)");
    init_mqtt();
}

void loop() {
    mqttClient.loop();
    if (!mqttClient.connected()) {
    if (millis() - lastReconnectAttempt > 5000) {
        lastReconnectAttempt = millis();
        // Attempt to reconnect
        if (reconnect()) {
            lastReconnectAttempt = 0;
        }
        }    
    }    

}

файл mqtt.cpp

#ifndef MQTT_H
#define MQTT_H
#include "config.h"

const char *mqtt_server = "m20.cloudmqtt.com"; // Имя сервера MQTT
const int mqtt_port = 17301; // Порт для подключения к серверу MQTT
const char *mqtt_user = "***********"; // Логи от сервер
const char *mqtt_pass = "******"; // Пароль от сервера


void callback(char* topic, byte* payload, unsigned int length);

void init_mqtt() {
  mqttClient.setServer(mqtt_server, mqtt_port);
  mqttClient.setCallback(callback);
}

void callback(char* topic, byte* payload, unsigned int length) { // Функция получения данных от сервера

}

boolean reconnect() {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (mqttClient.connect("ESP8266Client", mqtt_user, mqtt_pass)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqttClient.publish("outTopic", "hello world");//*************************************************************
      // ... and resubscribe
      mqttClient.subscribe("pg1/led1"); // подписывааемся по топик с данными для светодиода
      mqttClient.subscribe("pg1/led2"); // подписывааемся по топик с данными для светодиода
      mqttClient.subscribe("pg1/stopres"); // подписывааемся по топик с запретом на реакцию на фоторезистор
      mqttClient.subscribe("pg1/lightlevel"); // подписывааемся по топик с порогом освещенности
      mqttClient.subscribe("pg1/timezone"); // подписывааемся по топик с timezone
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
    }
    return mqttClient.connected();
}
#endif

файл config.h

#ifndef GLOBAL_H
#define GLOBAL_H

#include <Arduino.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>  
#include <PubSubClient.h> //"https://github.com/knolleary/pubsubclient.git"  

#define LED_PIN_1 5 // 1 LED
#define LED_PIN_2 12 //2 LED
#define REL_PIN_1 13 //1 relay
#define REL_PIN_2 14 //2 relay
#define SENSOR_PIN A0    // выберите входной контакт,к которому подключен фоторезистор (2)
#define TEMPHUM_PIN 4    // выберите входной контакт,к которому подключен датчик

unsigned long lastReconnectAttempt = 0;

WiFiClient espClient;
PubSubClient mqttClient(espClient);

void init_mqtt();
boolean reconnect();

#endif

На этапе компиляции получаю ошибку
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.mqttClient+0x0): multiple definition of `mqttClient'
.pioenvs\esp12e\src\main.cpp.o:(.bss.mqttClient+0x0): first defined here
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.espClient+0x0): multiple definition of `espClient'
.pioenvs\esp12e\src\main.cpp.o:(.bss.espClient+0x0): first defined here
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.lastReconnectAttempt+0x0): multiple definition of `lastReconnectAttempt'
.pioenvs\esp12e\src\main.cpp.o:(.bss.lastReconnectAttempt+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

Подскажите что я делаю не так

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

не так делаешь многофайловый праэкт

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Все. Прежде всего в ардуино IDE основной файл проекта ОБЯЗАН иметь расширение .ino и содержать процедуры setup() и loop(). Все остальные файлы ОБЯЗАНЫ иметь стандартные сишные расширения в имени файлов и находится в одном дирректории с основным файлом проекта. Название дирректория ОБЯЗЯНО быть копией имени основного файла проекта, но без расширения.

Antsanv
Offline
Зарегистрирован: 18.12.2018

А как?

Antsanv
Offline
Зарегистрирован: 18.12.2018

brokly пишет:

Все. Прежде всего в ардуино IDE основной файл проекта ОБЯЗАН иметь расширение .ino и содержать процедуры setup() и loop(). Все остальные файлы ОБЯЗАНЫ иметь стандартные сишные расширения в имени файлов и находится в одном дирректории с основным файлом проекта. Название дирректория ОБЯЗЯНО быть копией имени основного файла проекта, но без расширения.

Это PlatformIO. Там все делается именно как я написал. В смысле именования файлов.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

brokly пишет:

Все. Прежде всего в ардуино IDE ...bla-bla-bla...

1. Брукли, Уважаемый! Перечитай название темыю Там не про ИДЕ $)))

Antsanv пишет:

Подскажите что я делаю не так

2. Но частично Брукли прав. Платформио повторяет дуйствия АрдуиноИДЕ для совместимости. То есть сливает все файлы каталога в один. А ты два раза инклюдишь config.h. Вот и причина малтипл дефинишн. Отдельно только библиотеки компилируются.

Antsanv
Offline
Зарегистрирован: 18.12.2018

Но ведь я указываю 

#ifndef GLOBAL_H
02 #define GLOBAL_H

почему это не работает?

Green
Offline
Зарегистрирован: 01.10.2015

Лично я не понимаю зачем в config.h определять переменные и экземпляры класса! Зачем? В чём смысел?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Antsanv пишет:

Но ведь я указываю 

#ifndef GLOBAL_H
02 #define GLOBAL_H

почему это не работает?

Разреши поинтересоваться: а как, по твоему, это должно работать?

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

wdrakula пишет:

Разреши поинтересоваться: а как, по твоему, это должно работать?

примерна, как 

#pragma once

b707
Offline
Зарегистрирован: 26.05.2017

Antsanv пишет:

Но ведь я указываю 

#ifndef GLOBAL_H
02 #define GLOBAL_H

почему это не работает?

почему не работает? - работает.

Эта конструкция обеспечивает, чтобы ваш config.h не включался дважды в один и тот же компилируемый модуль. Но модуля-то у вас два - mqtt.cpp и main.cpp! поэтому config.h включается в программу дважды и все переменные, в нем описанные - получают двойное описание, о чем вам компилятор и сообщает.

Чтобы такого не было, глобальные переменные следует описывать только в .cpp файлах, а чтобы использовать их в других модулях программы - пользоваться квалификатором EXTERN

Green
Offline
Зарегистрирован: 01.10.2015

И как он ДВАЖДЫ включится в ОДИН И ТОТ ЖЕ МОДУЛЬ? Хоть с 

#ifndef GLOBAL_H
02

#define GLOBAL_H

хоть без?

Antsanv
Offline
Зарегистрирован: 18.12.2018

Green пишет:

Лично я не понимаю зачем в config.h определять переменные и экземпляры класса! Зачем? В чём смысел?

Чтобы все в одном месте было. А как правильно?

b707
Offline
Зарегистрирован: 26.05.2017

Green пишет:

И как он ДВАЖДЫ включится в ОДИН И ТОТ ЖЕ МОДУЛЬ?

а кто сказал что он в один модуль включился?

Antsanv
Offline
Зарегистрирован: 18.12.2018

Спасибо, с переменными понятно.

Но как быть с 

WiFiClient espClient;
PubSubClient mqttClient(espClient);

Они используются в двух файлах.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

DetSimen пишет:

wdrakula пишет:

Разреши поинтересоваться: а как, по твоему, это должно работать?

примерна, как 

#pragma once

виноват. не заметил, что все правильно написано, #endif в конце файла.

И ощибки у линковщика - значит я был неправ и платформио, все-таки, компилирует отдельно. Следовательно правильный ответ у Б707.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

wdrakula пишет:

1. Брукли, Уважаемый! Перечитай название темыю Там не про ИДЕ $)))

Да да да да... да..

Antsanv
Offline
Зарегистрирован: 18.12.2018

Извините, может я глупые вопросы задаю, но все же как быть с Но как быть с 

WiFiClient espClient;
PubSubClient mqttClient(espClient); 

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Antsanv пишет:

Извините, может я глупые вопросы задаю, но все же как быть с Но как быть с 

WiFiClient espClient;
PubSubClient mqttClient(espClient); 

Вам же ответили !

b707 пишет:

Чтобы такого не было, глобальные переменные следует описывать только в .cpp файлах, а чтобы использовать их в других модулях программы - пользоваться квалификатором EXTERN